将Feature/XP.Common和Feature/XP.Hardware分支合并至Develop/XP.forHardwareAndCommon,完善XPapp注册和相关硬件类库通用类库功能。
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
using System.Configuration;
|
||||
using XP.Common.Configs;
|
||||
using XP.Common.Dump.Configs;
|
||||
|
||||
namespace XP.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 通用配置加载工具(读取App.config)
|
||||
/// </summary>
|
||||
public static class ConfigLoader
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载Serilog配置
|
||||
/// </summary>
|
||||
public static SerilogConfig LoadSerilogConfig()
|
||||
{
|
||||
var config = new SerilogConfig();
|
||||
|
||||
var logPath = ConfigurationManager.AppSettings["Serilog:LogPath"];
|
||||
if (!string.IsNullOrEmpty(logPath)) config.LogPath = logPath;
|
||||
|
||||
var minLevel = ConfigurationManager.AppSettings["Serilog:MinimumLevel"];
|
||||
if (!string.IsNullOrEmpty(minLevel)) config.MinimumLevel = minLevel;
|
||||
|
||||
var enableConsole = ConfigurationManager.AppSettings["Serilog:EnableConsole"];
|
||||
if (bool.TryParse(enableConsole, out var console)) config.EnableConsole = console;
|
||||
|
||||
var rollingInterval = ConfigurationManager.AppSettings["Serilog:RollingInterval"];
|
||||
if (!string.IsNullOrEmpty(rollingInterval)) config.RollingInterval = rollingInterval;
|
||||
|
||||
var fileSize = ConfigurationManager.AppSettings["Serilog:FileSizeLimitMB"];
|
||||
if (long.TryParse(fileSize, out var size)) config.FileSizeLimitMB = size;
|
||||
|
||||
var retainCount = ConfigurationManager.AppSettings["Serilog:RetainedFileCountLimit"];
|
||||
if (int.TryParse(retainCount, out var count)) config.RetainedFileCountLimit = count;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载SQLite配置
|
||||
/// </summary>
|
||||
public static SqliteConfig LoadSqliteConfig()
|
||||
{
|
||||
var config = new SqliteConfig();
|
||||
|
||||
var dbPath = ConfigurationManager.AppSettings["Sqlite:DbFilePath"];
|
||||
if (!string.IsNullOrEmpty(dbPath)) config.DbFilePath = dbPath;
|
||||
|
||||
var timeout = ConfigurationManager.AppSettings["Sqlite:ConnectionTimeout"];
|
||||
if (int.TryParse(timeout, out var t)) config.ConnectionTimeout = t;
|
||||
|
||||
var createIfNotExists = ConfigurationManager.AppSettings["Sqlite:CreateIfNotExists"];
|
||||
if (bool.TryParse(createIfNotExists, out var c)) config.CreateIfNotExists = c;
|
||||
|
||||
var enableWal = ConfigurationManager.AppSettings["Sqlite:EnableWalMode"];
|
||||
if (bool.TryParse(enableWal, out var w)) config.EnableWalMode = w;
|
||||
|
||||
var enableSqlLog = ConfigurationManager.AppSettings["Sqlite:EnableSqlLogging"];
|
||||
if (bool.TryParse(enableSqlLog, out var l)) config.EnableSqlLogging = l;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载 Dump 配置 | Load Dump configuration
|
||||
/// </summary>
|
||||
public static DumpConfig LoadDumpConfig()
|
||||
{
|
||||
var config = new DumpConfig();
|
||||
|
||||
var storagePath = ConfigurationManager.AppSettings["Dump:StoragePath"];
|
||||
if (!string.IsNullOrEmpty(storagePath)) config.StoragePath = storagePath;
|
||||
|
||||
var enableScheduled = ConfigurationManager.AppSettings["Dump:EnableScheduledDump"];
|
||||
if (bool.TryParse(enableScheduled, out var enabled)) config.EnableScheduledDump = enabled;
|
||||
|
||||
var interval = ConfigurationManager.AppSettings["Dump:ScheduledIntervalMinutes"];
|
||||
if (int.TryParse(interval, out var min)) config.ScheduledIntervalMinutes = min;
|
||||
|
||||
var sizeLimit = ConfigurationManager.AppSettings["Dump:MiniDumpSizeLimitMB"];
|
||||
if (long.TryParse(sizeLimit, out var size)) config.MiniDumpSizeLimitMB = size;
|
||||
|
||||
var retentionDays = ConfigurationManager.AppSettings["Dump:RetentionDays"];
|
||||
if (int.TryParse(retentionDays, out var days)) config.RetentionDays = days;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace XP.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程管理工具类 | Process Management Helper
|
||||
/// 提供启动外部程序、窗口置前等通用功能 | Provides common functions like launching external programs and bringing windows to front
|
||||
/// </summary>
|
||||
public static class ProcessHelper
|
||||
{
|
||||
#region Win32 API
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool IsIconic(IntPtr hWnd);
|
||||
|
||||
private const int SW_RESTORE = 9;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 启动或激活外部程序 | Start or activate an external program
|
||||
/// </summary>
|
||||
/// <param name="exePath">可执行文件完整路径 | Full path to the executable</param>
|
||||
/// <param name="singleInstance">是否单实例模式:true=已运行则置前,false=直接启动新实例 | Single instance mode: true=activate if running, false=always start new instance</param>
|
||||
/// <returns>操作结果 | Operation result</returns>
|
||||
public static ProcessResult StartOrActivate(string exePath, bool singleInstance = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(exePath))
|
||||
{
|
||||
return ProcessResult.Fail("程序路径未配置 | Program path not configured");
|
||||
}
|
||||
|
||||
if (!File.Exists(exePath))
|
||||
{
|
||||
return ProcessResult.Fail($"程序文件不存在: {exePath} | Program file not found: {exePath}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 获取进程名(不含扩展名)| Get process name (without extension)
|
||||
var processName = Path.GetFileNameWithoutExtension(exePath);
|
||||
|
||||
if (singleInstance)
|
||||
{
|
||||
var processes = Process.GetProcessesByName(processName);
|
||||
|
||||
if (processes.Length > 0)
|
||||
{
|
||||
// 程序已运行,将窗口置前 | Program already running, bring window to front
|
||||
var process = processes[0];
|
||||
var hWnd = process.MainWindowHandle;
|
||||
|
||||
if (hWnd != IntPtr.Zero)
|
||||
{
|
||||
BringToFront(hWnd);
|
||||
}
|
||||
|
||||
return ProcessResult.Activated();
|
||||
}
|
||||
}
|
||||
|
||||
// 启动程序 | Start program
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = exePath,
|
||||
UseShellExecute = true
|
||||
});
|
||||
|
||||
return ProcessResult.Started();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ProcessResult.Fail($"操作失败: {ex.Message} | Operation failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断指定进程是否正在运行 | Check if a process is running
|
||||
/// </summary>
|
||||
/// <param name="processName">进程名(不含扩展名)| Process name (without extension)</param>
|
||||
/// <returns>是否运行中 | Whether the process is running</returns>
|
||||
public static bool IsProcessRunning(string processName)
|
||||
{
|
||||
return Process.GetProcessesByName(processName).Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据可执行文件路径查找已运行的进程 | Find a running process by executable file path
|
||||
/// 通过进程名匹配并验证完整路径,确保找到的是同一个程序 | Matches by process name and verifies full path
|
||||
/// </summary>
|
||||
/// <param name="exePath">可执行文件完整路径 | Full path to the executable</param>
|
||||
/// <returns>找到的进程对象,未找到返回 null | The found process, or null if not found</returns>
|
||||
public static Process FindRunningProcess(string exePath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(exePath))
|
||||
return null;
|
||||
|
||||
var processName = Path.GetFileNameWithoutExtension(exePath);
|
||||
var normalizedTarget = NormalizePath(exePath);
|
||||
|
||||
try
|
||||
{
|
||||
var processes = Process.GetProcessesByName(processName);
|
||||
foreach (var proc in processes)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 验证完整路径匹配,避免同名不同路径的进程误关联
|
||||
var procPath = proc.MainModule?.FileName;
|
||||
if (procPath != null && string.Equals(NormalizePath(procPath), normalizedTarget, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return proc;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 无法访问进程信息(权限不足等),跳过
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// GetProcessesByName 异常,返回 null
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标准化文件路径,用于路径比较 | Normalize file path for comparison
|
||||
/// </summary>
|
||||
private static string NormalizePath(string path)
|
||||
{
|
||||
return Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将窗口置前显示 | Bring a window to the foreground
|
||||
/// </summary>
|
||||
/// <param name="hWnd">窗口句柄 | Window handle</param>
|
||||
public static void BringToFront(IntPtr hWnd)
|
||||
{
|
||||
if (hWnd == IntPtr.Zero) return;
|
||||
|
||||
// 如果窗口被最小化,先恢复 | If window is minimized, restore it first
|
||||
if (IsIconic(hWnd))
|
||||
{
|
||||
ShowWindow(hWnd, SW_RESTORE);
|
||||
}
|
||||
|
||||
SetForegroundWindow(hWnd);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 进程操作结果 | Process Operation Result
|
||||
/// </summary>
|
||||
public class ProcessResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否成功 | Whether the operation succeeded
|
||||
/// </summary>
|
||||
public bool Success { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为新启动(false表示激活已有窗口)| Whether it was newly started (false means activated existing window)
|
||||
/// </summary>
|
||||
public bool IsNewlyStarted { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 错误信息 | Error message
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建启动成功结果 | Create a started result
|
||||
/// </summary>
|
||||
public static ProcessResult Started() => new() { Success = true, IsNewlyStarted = true };
|
||||
|
||||
/// <summary>
|
||||
/// 创建激活成功结果 | Create an activated result
|
||||
/// </summary>
|
||||
public static ProcessResult Activated() => new() { Success = true, IsNewlyStarted = false };
|
||||
|
||||
/// <summary>
|
||||
/// 创建失败结果 | Create a failed result
|
||||
/// </summary>
|
||||
public static ProcessResult Fail(string errorMessage) => new() { Success = false, ErrorMessage = errorMessage };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user