A: 新增ExceptionExpand异常处理类及相关枚举 (Infrastructure/ExceptionExpand.cs)

A: 新增全局Process缓存类 (Infrastructure/GlobalCaches/ProcessCache.cs)
A: 新增WinDivert封装和PacketSniffer数据包捕获功能 (WinDivertNet/WinDivertWrapper)
A: 新增Todo文档 (ClientApp/doc/Todo.md)
U: 配置生成路由显示 (ClientApp/src/constants/app.ts)
U: WebPanel新增数据包捕获触发逻辑 (Shell/Views/WebPanel.xaml.cs)
U: 配置Shell项目加载WinDivert相关文件 (Shell/Shell.csproj)
This commit is contained in:
jimmy committed 2025-05-18 22:10:03 +08:00
1 parent 078e59ae6b
commit ad2514e044
21 files changed
+1560 -71

No files matched your search

+49
View File
@@ -0,0 +1,49 @@
namespace Infrastructure;
public class ExceptionExpand : Exception
{
/// <summary>
/// 默认异常编码
/// </summary>
private const long DefaultCode = -1;
public string ErrorMessage { get; private set; } = "";
public long ErrorCode { get; private set; } = DefaultCode;
public string Suggestion { get; private set; } = "";
private ExceptionExpand()
{
}
public ExceptionExpand(long errorCode, string massage, string solution) : base(
massage)
{
ErrorCode = errorCode;
Suggestion = solution;
}
public ExceptionExpand(long errorCode, string massage, string solution, Exception? innerException) : base(
massage, innerException)
{
ErrorCode = errorCode;
Suggestion = solution;
}
public override string ToString()
{
return $"Error Code: {ErrorCode}\nMessage: {Message}\nSuggestion: {Suggestion}\n{base.ToString()}";
}
}
public class ExceptionEnum
{
// region 系统常见错误本地化
/// <summary>
/// 进程信息获取失败
/// </summary>
public static readonly ExceptionExpand ProcessGetException = new(100001L, "进程消息获取失败,指定线程可能不存在或已关闭!", "以管理员权限重试!");
// endregion
}
@@ -0,0 +1,58 @@
using System.Diagnostics;
using Infrastructure.Models;
namespace Infrastructure.GlobalCaches;
/// <summary>
/// 进程信息缓存
/// </summary>
public sealed class ProcessCache
{
private static readonly Lazy<ProcessCache> _instance = new Lazy<ProcessCache>(() => new ProcessCache());
public static ProcessCache Instance => _instance.Value;
public record ProcessCacheKey(int Pid, DateTime StartTime);
public ProcessCacheKey GetProcessKey(int pid)
{
var process = Process.GetProcessById(pid);
return new ProcessCacheKey(pid, process.StartTime);
}
// 私有构造函数,禁止外部创建实例
private ProcessCache()
{
// 初始化缓存等操作
}
// 示例缓存字段
private readonly Dictionary<ProcessCacheKey, ProgramInfo> _cache = new Dictionary<ProcessCacheKey, ProgramInfo>();
// 设置缓存
public void Set(ProcessCacheKey key, ProgramInfo value)
{
lock (_cache)
{
_cache[key] = value;
}
}
// 获取缓存
public ProgramInfo? Get(ProcessCacheKey key)
{
lock (_cache)
{
return _cache.GetValueOrDefault(key);
}
}
// 移除缓存
public void Remove(ProcessCacheKey key)
{
lock (_cache)
{
_cache.Remove(key);
}
}
}
+7 -1
View File
@@ -1,13 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.21" />
<PackageReference Include="System.Drawing.Common" Version="10.0.0-preview.4.25258.110" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WinDivertNet\WinDivertNet.csproj" />
</ItemGroup>
</Project>
+10 -10
View File
@@ -1,16 +1,11 @@
namespace Infrastructure.Models;
public class D
public class ProgramInfo
{
/// <summary>
/// 网络信息
/// </summary>
public List<NetInfo> NetInfos { get; set; }
/// <summary>
/// 进程名称
/// </summary>
public string ProcessName { get; set; }
public string ProcessName { get; set; } = "";
/// <summary>
/// 进程ID
@@ -40,7 +35,7 @@ public class D
/// <summary>
/// 占用内存
/// </summary>
public string UseMemory { get; set; }
public long UseMemory { get; set; }
/// <summary>
/// 线程数
@@ -80,7 +75,12 @@ public class D
/// <summary>
/// 版权
/// </summary>
public string? Copyright { get; set; }
public string? LegalCopyright { get; set; }
/// <summary>
/// 图标
/// </summary>
public string IconBase64 { get; set; } = "";
}
/// <summary>
@@ -151,5 +151,5 @@ public class NetInfo
/// <summary>
/// 接收字节数
/// </summary>
public long TotalRecvBytes { get; set; }
public long TotalReceiveBytes { get; set; }
}
+32
View File
@@ -0,0 +1,32 @@
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
namespace Infrastructure.utils;
public static class IconHelper
{
[DllImport("Shell32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);
/// <summary>
/// 获取 ICON
/// </summary>
/// <param name="exePath"></param>
/// <returns></returns>
public static string GetIconBase64(string? exePath)
{
if (exePath == null && !File.Exists(exePath)) return "";
IntPtr hIcon = ExtractIcon(IntPtr.Zero, exePath, 0);
if (hIcon == IntPtr.Zero) return "";
using Icon icon = Icon.FromHandle(hIcon);
using Bitmap bmp = icon.ToBitmap();
using MemoryStream ms = new MemoryStream();
// 保存为 PNG 格式
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] bytes = ms.ToArray();
return Convert.ToBase64String(bytes);
}
}
+28 -23
View File
@@ -9,7 +9,27 @@ using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
using Microsoft.Diagnostics.Tracing.Session;
public class NetUtils
public enum TCP_TABLE_CLASS
{
TCP_TABLE_BASIC_LISTENER,
TCP_TABLE_BASIC_CONNECTIONS,
TCP_TABLE_BASIC_ALL,
TCP_TABLE_OWNER_PID_LISTENER,
TCP_TABLE_OWNER_PID_CONNECTIONS,
TCP_TABLE_OWNER_PID_ALL, // 使用这个
TCP_TABLE_OWNER_MODULE_LISTENER,
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
TCP_TABLE_OWNER_MODULE_ALL
}
public enum UDP_TABLE_CLASS
{
UDP_TABLE_BASIC,
UDP_TABLE_OWNER_PID,
UDP_TABLE_OWNER_MODULE
}
public static class NetUtils
{
/// <summary>
/// 联网内容监视
@@ -63,19 +83,6 @@ public class NetUtils
}
}
private enum TCP_TABLE_CLASS
{
TCP_TABLE_BASIC_LISTENER,
TCP_TABLE_BASIC_CONNECTIONS,
TCP_TABLE_BASIC_ALL,
TCP_TABLE_OWNER_PID_LISTENER,
TCP_TABLE_OWNER_PID_CONNECTIONS,
TCP_TABLE_OWNER_PID_ALL, // 我们使用这个
TCP_TABLE_OWNER_MODULE_LISTENER,
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
TCP_TABLE_OWNER_MODULE_ALL
}
/// <summary>
/// 获取所有连接
/// </summary>
@@ -87,8 +94,8 @@ public class NetUtils
try
{
if (GetExtendedTcpTable(tcpTablePtr, ref buffSize, true, 2, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, 0) ==
0)
if (GetExtendedTcpTable(tcpTablePtr, ref buffSize, true, 2,
TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, 0) == 0)
{
int rowCount = Marshal.ReadInt32(tcpTablePtr);
IntPtr rowPtr = IntPtr.Add(tcpTablePtr, 4);
@@ -113,7 +120,11 @@ public class NetUtils
}
}
// 网络字节序转主机字节序
/// <summary>
/// 网络字节序转主机字节序
/// </summary>
/// <param name="netshort"></param>
/// <returns></returns>
private static ushort ntohs(ushort netshort) => (ushort)((netshort >> 8) | (netshort << 8));
[DllImport("iphlpapi.dll", SetLastError = true)]
@@ -153,12 +164,6 @@ public class NetUtils
UDP_TABLE_CLASS tableClass,
uint reserved = 0);
public enum UDP_TABLE_CLASS
{
UDP_TABLE_BASIC,
UDP_TABLE_OWNER_PID,
UDP_TABLE_OWNER_MODULE
}
[StructLayout(LayoutKind.Sequential)]
public struct MIB_UDPROW_OWNER_PID
+65 -36
View File
@@ -1,21 +1,19 @@
using System.Text.Json;
namespace Infrastructure.utils;
using Infrastructure.GlobalCaches;
using Infrastructure.Models;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
public static class SysInfoUtils
{
/// <summary>
/// 程序自身信息
/// </summary>
/// <returns></returns>
public static string GetProgramDiagnostics()
{
var sb = new StringBuilder();
@@ -53,48 +51,79 @@ public static class SysInfoUtils
return sb.ToString();
}
public static void InspectProcess(int pid)
/// <summary>
/// 获取指定进程的信息
/// </summary>
/// <param name="pid"></param>
/// <returns></returns>
/// <exception cref="ExceptionExpand"></exception>
public static ProgramInfo InspectProcess(int pid)
{
try
{
var proc = Process.GetProcessById(pid);
Console.WriteLine($"进程名称:{proc.ProcessName}");
Console.WriteLine($"进程ID:{proc.Id}");
Console.WriteLine($"启动时间:{proc.StartTime}");
Console.WriteLine($"是否退出:{proc.HasExited}");
Console.WriteLine($"退出时间:{proc.ExitTime}");
Console.WriteLine($"退出代码:{proc.ExitCode}");
Console.WriteLine($"占用内存:{FormatBytes(proc.WorkingSet64)}");
Console.WriteLine($"线程数:{proc.Threads.Count}");
Console.WriteLine($"主模块路径:{proc.MainModule?.FileName}");
Console.WriteLine($"启动文件名:{proc.MainModule?.ModuleName}");
var serialize = JsonSerializer.Serialize(proc.MainModule);
Console.WriteLine($"YYY:{serialize}");
var filePath = proc.MainModule?.FileName;
if (filePath != null)
{
var versionInfo = FileVersionInfo.GetVersionInfo(filePath);
#region 检查缓存
Console.WriteLine($"文件描述:{versionInfo.FileDescription}");
Console.WriteLine($"产品名称:{versionInfo.ProductName}");
Console.WriteLine($"公司名称:{versionInfo.CompanyName}");
Console.WriteLine($"版本号:{versionInfo.FileVersion}");
Console.WriteLine($"版权:{versionInfo.LegalCopyright}");
var serialize1 = JsonSerializer.Serialize(versionInfo);
Console.WriteLine($"XXX:{serialize1}");
var pck = new ProcessCache.ProcessCacheKey(pid, proc.StartTime);
var programInfo = ProcessCache.Instance.Get(pck);
if (programInfo != null)
{
return programInfo;
}
#endregion
#region 获取进程信息
var exeInfo = new ProgramInfo
{
ProcessName = proc.ProcessName,
ProcessId = proc.Id,
StartTime = proc.StartTime,
HasExited = proc.HasExited,
ExitTime = proc.ExitTime,
ExitCode = proc.ExitCode,
UseMemory = proc.WorkingSet64,
ThreadCount = proc.Threads.Count,
MainModulePath = proc.MainModule?.FileName,
MainModuleName = proc.MainModule?.ModuleName
};
// MainModule 是一个涉及 native 调用的属性,不建议频繁调用,尤其在枚举大量进程时可能影响性能。
if (exeInfo.MainModulePath != null)
{
var versionInfo = FileVersionInfo.GetVersionInfo(exeInfo.MainModulePath);
exeInfo.FileDescription = versionInfo.FileDescription;
exeInfo.ProductName = versionInfo.ProductName;
exeInfo.CompanyName = versionInfo.CompanyName;
exeInfo.Version = versionInfo.FileVersion;
exeInfo.LegalCopyright = versionInfo.LegalCopyright;
}
// 获取软件 Icon 【不一定存在】
var iconBase64 = IconHelper.GetIconBase64(exeInfo.MainModulePath);
exeInfo.IconBase64 = iconBase64;
#endregion
ProcessCache.Instance.Set(pck, exeInfo);
return exeInfo;
}
catch (Exception ex)
// 只捕获能遇见的异常
catch (ArgumentException ex)
{
Console.WriteLine($"获取进程信息失败:{ex.Message}");
throw ExceptionEnum.ProcessGetException;
}
}
private static string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
string[] sizes = ["B", "KB", "MB", "GB", "TB"];
double len = bytes;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)