A:添加底部ICON通知
This commit is contained in:
1 parent
efc298e148
commit
8b8b695f0d
13 files changed
+798
-71
No files matched your search
@@ -151,7 +151,7 @@ namespace Common.Utils
|
||||
totalSpeed.UploadSpeed += speed.UploadSpeed;
|
||||
}
|
||||
|
||||
Log.Info($"总网速 - 下载: {totalSpeed.DownloadSpeedText}, 上传: {totalSpeed.UploadSpeedText}");
|
||||
// Log.Info($"总网速 - 下载: {totalSpeed.DownloadSpeedText}, 上传: {totalSpeed.UploadSpeedText}");
|
||||
return totalSpeed;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Common.Utils
|
||||
// 跳过环回接口
|
||||
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback)
|
||||
{
|
||||
Log.Info($"跳过环回接口: {ni.Name}");
|
||||
//Log.Info($"跳过环回接口: {ni.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace Common.Utils
|
||||
}
|
||||
}
|
||||
|
||||
Log.Info($"总网速 - 下载: {totalSpeed.DownloadSpeedText}, 上传: {totalSpeed.UploadSpeedText}");
|
||||
// Log.Info($"总网速 - 下载: {totalSpeed.DownloadSpeedText}, 上传: {totalSpeed.UploadSpeedText}");
|
||||
|
||||
return totalSpeed;
|
||||
}
|
||||
@@ -308,4 +308,4 @@ namespace Common.Utils
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEvent_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F4d_003F09175cdc_003FTraceEvent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWebSocketServer_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7d96aff8e344c1d9aa8042f229d493cae00_003Fc6_003F2f09550a_003FWebSocketServer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWebView2_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8aca2f2c90e1454c825fc8b69c53a97e14268_003F06_003F22dc0e77_003FWebView2_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWindow_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd079e839ea2040f09d8282baf64f01edf61928_003Fab_003F96a4af57_003FWindow_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=f4a8c497_002D43fb_002D4de1_002D9ffa_002D84076d7db2c5/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="Test1" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||
<TestAncestor>
|
||||
<TestId>NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.Tests.Test1</TestId>
|
||||
|
||||
@@ -20,12 +20,16 @@ using Infrastructure.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog.Events;
|
||||
using Shell;
|
||||
using Shell.UserControls;
|
||||
using Shell.Utils;
|
||||
using Shell.Views;
|
||||
using Utils.ETW.Etw;
|
||||
using Utils.Firewall;
|
||||
|
||||
namespace NetVizor;
|
||||
|
||||
using System.Windows.Forms; // 引用 Windows Forms 命名空间
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
@@ -42,16 +46,20 @@ public partial class App : System.Windows.Application
|
||||
|
||||
// 启动服务(如 WebSocket、HTTP、端口监听等)
|
||||
// StartMyServer();
|
||||
|
||||
// NetView
|
||||
// var netView = new NetView();
|
||||
// netView.Show();
|
||||
|
||||
Mouth();
|
||||
// NetView 网络监看
|
||||
var netView = new NetView();
|
||||
netView.Show();
|
||||
|
||||
// Mouth();
|
||||
|
||||
|
||||
// 网速监视
|
||||
// var window = new NetView();
|
||||
// window.Show();
|
||||
|
||||
// 设置应用程序在关闭最后一个窗口时不自动退出
|
||||
this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
|
||||
}
|
||||
|
||||
private async void Mouth()
|
||||
@@ -59,7 +67,7 @@ public partial class App : System.Windows.Application
|
||||
var firewallService = new FirewallService();
|
||||
// 防火墙状态
|
||||
// var statusAsync = await firewallService.GetStatusAsync();
|
||||
var rulesAsync =await firewallService.GetRulesAsync();
|
||||
var rulesAsync = await firewallService.GetRulesAsync();
|
||||
Console.WriteLine(JsonHelper.ToJson(rulesAsync));
|
||||
}
|
||||
|
||||
@@ -405,6 +413,10 @@ public partial class App : System.Windows.Application
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取防火墙信息
|
||||
|
||||
#endregion
|
||||
|
||||
#region 取消订阅
|
||||
|
||||
server.Post("/api/unsubscribe", async (context) =>
|
||||
@@ -516,4 +528,4 @@ public class SubscriptionAppInfo : SubscriptionInfo
|
||||
// 再有,“协议和端口”中的协议类型也有很多,我们也要展示。比如它甚至能指定用户,可以选择用户和组。
|
||||
// 所以基于上,我们几乎是重写了防火墙的页面。
|
||||
// 我现在需要你基于这个能获取到的信息(可能有些我没提到),使用html完成一个防火墙的看板,要点击某个规则可以编辑,可以新增。
|
||||
// 新增的窗口和交互都需要完成,数据的展示也需要完成。你用假数据替代数据填充即可,要求界面要现代化,美观,优雅
|
||||
// 新增的窗口和交互都需要完成,数据的展示也需要完成。你用假数据替代数据填充即可,要求界面要现代化,美观,优雅
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -6,14 +6,22 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms> <!-- 加上这句,才能正确启用 Forms 支持 -->
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Assets\Icons\"/>
|
||||
<Folder Include="wwwroot\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3240.44" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="10.0.0-preview.6.25358.103"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Windows.Forms"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -30,6 +38,10 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="WinDivert.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Remove="Assets\Icons\app.ico"/>
|
||||
<Content Include="Assets\Icons\app.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Shell.UserControls
|
||||
/// <summary>
|
||||
/// Interaction logic for NetworkMonitorView.xaml
|
||||
/// </summary>
|
||||
public partial class NetworkMonitorView : UserControl
|
||||
public partial class NetworkMonitorView : System.Windows.Controls.UserControl
|
||||
{
|
||||
private NetworkMonitorViewModel _viewModel;
|
||||
|
||||
@@ -38,4 +38,4 @@ namespace Shell.UserControls
|
||||
_viewModel?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<Window x:Class="Shell.UserControls.TrayMenuWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Shell.UserControls"
|
||||
mc:Ignorable="d"
|
||||
Title="TrayMenu"
|
||||
Height="200" Width="180"
|
||||
WindowStyle="None"
|
||||
AllowsTransparency="True"
|
||||
Background="Transparent"
|
||||
Topmost="True"
|
||||
ShowInTaskbar="False"
|
||||
ResizeMode="NoResize"
|
||||
Deactivated="Window_Deactivated">
|
||||
|
||||
<Window.Resources>
|
||||
<!-- 菜单项样式 -->
|
||||
<Style x:Key="MenuItemStyle" TargetType="Border">
|
||||
<Setter Property="Padding" Value="15,8" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#E3F2FD" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- 图标样式 -->
|
||||
<Style x:Key="IconStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
<Setter Property="Foreground" Value="#2196F3" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="Margin" Value="0,0,10,0" />
|
||||
</Style>
|
||||
|
||||
<!-- 文本样式 -->
|
||||
<Style x:Key="TextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="Foreground" Value="#333333" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<!-- 分隔线样式 -->
|
||||
<Style x:Key="SeparatorStyle" TargetType="Rectangle">
|
||||
<Setter Property="Height" Value="1" />
|
||||
<Setter Property="Fill" Value="#E0E0E0" />
|
||||
<Setter Property="Margin" Value="10,5" />
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Border Background="White"
|
||||
CornerRadius="8"
|
||||
BorderBrush="#E0E0E0"
|
||||
BorderThickness="1">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect ShadowDepth="3"
|
||||
Direction="315"
|
||||
Color="#40000000"
|
||||
Opacity="0.3"
|
||||
BlurRadius="10" />
|
||||
</Border.Effect>
|
||||
|
||||
<StackPanel Margin="5">
|
||||
<!-- 打开主窗口 -->
|
||||
<Border Style="{StaticResource MenuItemStyle}"
|
||||
MouseLeftButtonDown="ShowMainWindow_Click">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="" Style="{StaticResource IconStyle}" />
|
||||
<TextBlock Text="打开主窗口" Style="{StaticResource TextStyle}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<Rectangle Style="{StaticResource SeparatorStyle}" />
|
||||
|
||||
<!-- 最小化到托盘 -->
|
||||
<Border Style="{StaticResource MenuItemStyle}"
|
||||
MouseLeftButtonDown="HideToTray_Click">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="" Style="{StaticResource IconStyle}" />
|
||||
<TextBlock Text="最小化到托盘" Style="{StaticResource TextStyle}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 关于 -->
|
||||
<Border Style="{StaticResource MenuItemStyle}"
|
||||
MouseLeftButtonDown="About_Click">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="" Style="{StaticResource IconStyle}" />
|
||||
<TextBlock Text="关于" Style="{StaticResource TextStyle}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<Rectangle Style="{StaticResource SeparatorStyle}" />
|
||||
|
||||
<!-- 退出程序 -->
|
||||
<Border Style="{StaticResource MenuItemStyle}"
|
||||
MouseLeftButtonDown="ExitApplication_Click">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text=""
|
||||
Style="{StaticResource IconStyle}"
|
||||
Foreground="#F44336" />
|
||||
<TextBlock Text="退出程序"
|
||||
Style="{StaticResource TextStyle}"
|
||||
Foreground="#F44336" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</Window>
|
||||
@@ -0,0 +1,256 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Shell.UserControls;
|
||||
|
||||
public partial class TrayMenuWindow : Window
|
||||
{
|
||||
public event Action OnShowMainWindow;
|
||||
public event Action OnExitApplication;
|
||||
public event Action OnHideToTray;
|
||||
|
||||
// 菜单的固定尺寸(与XAML中设置的一致)
|
||||
private const double MENU_WIDTH = 180;
|
||||
private const double MENU_HEIGHT = 200;
|
||||
|
||||
public TrayMenuWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Loaded += TrayMenuWindow_Loaded;
|
||||
|
||||
// 确保窗口使用Per-Monitor DPI Awareness
|
||||
this.SourceInitialized += (s, e) =>
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(this).Handle;
|
||||
var source = HwndSource.FromHwnd(hwnd);
|
||||
if (source != null)
|
||||
{
|
||||
source.AddHook(WndProc);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||
{
|
||||
// 处理DPI变化消息
|
||||
const int WM_DPICHANGED = 0x02E0;
|
||||
if (msg == WM_DPICHANGED)
|
||||
{
|
||||
// DPI发生变化时可以在这里处理
|
||||
Console.WriteLine("DPI changed detected");
|
||||
}
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
private void TrayMenuWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// 添加淡入动画
|
||||
// var fadeIn = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(200));
|
||||
// this.BeginAnimation(OpacityProperty, fadeIn);
|
||||
|
||||
// 添加缩放动画
|
||||
// var scaleTransform = new System.Windows.Media.ScaleTransform(0.8, 0.8);
|
||||
// this.RenderTransform = scaleTransform;
|
||||
// this.RenderTransformOrigin = new System.Windows.Point(0.5, 0.5);
|
||||
|
||||
// var scaleXAnimation = new DoubleAnimation(0.8, 1, TimeSpan.FromMilliseconds(200));
|
||||
// var scaleYAnimation = new DoubleAnimation(0.8, 1, TimeSpan.FromMilliseconds(200));
|
||||
|
||||
// scaleXAnimation.EasingFunction = new QuadraticEase();
|
||||
// scaleYAnimation.EasingFunction = new QuadraticEase();
|
||||
|
||||
// scaleTransform.BeginAnimation(System.Windows.Media.ScaleTransform.ScaleXProperty, scaleXAnimation);
|
||||
// scaleTransform.BeginAnimation(System.Windows.Media.ScaleTransform.ScaleYProperty, scaleYAnimation);
|
||||
}
|
||||
|
||||
public void ShowAt(int x, int y)
|
||||
{
|
||||
// 使用主显示器工作区域的旧方法(保留向后兼容)
|
||||
var workArea = SystemParameters.WorkArea;
|
||||
var customWorkArea = new Shell.Utils.TrayIconManager.RECT
|
||||
{
|
||||
Left = (int)workArea.Left,
|
||||
Top = (int)workArea.Top,
|
||||
Right = (int)workArea.Right,
|
||||
Bottom = (int)workArea.Bottom
|
||||
};
|
||||
ShowAtWithWorkArea(x, y, customWorkArea);
|
||||
}
|
||||
|
||||
public void ShowAtWithWorkArea(int x, int y, Shell.Utils.TrayIconManager.RECT workArea)
|
||||
{
|
||||
Console.WriteLine("=== TrayMenu ShowAtWithWorkArea Debug ===");
|
||||
Console.WriteLine($"输入鼠标位置: X={x}, Y={y}");
|
||||
Console.WriteLine(
|
||||
$"使用工作区域: Left={workArea.Left}, Top={workArea.Top}, Right={workArea.Right}, Bottom={workArea.Bottom}");
|
||||
Console.WriteLine($"工作区域尺寸: Width={workArea.Right - workArea.Left}, Height={workArea.Bottom - workArea.Top}");
|
||||
Console.WriteLine($"菜单尺寸: Width={MENU_WIDTH}, Height={MENU_HEIGHT}");
|
||||
|
||||
// 获取当前窗口的DPI缩放信息
|
||||
var dpiScale = GetDpiScale();
|
||||
Console.WriteLine($"窗口DPI缩放: X={dpiScale.DpiScaleX:F2}, Y={dpiScale.DpiScaleY:F2}");
|
||||
|
||||
// 计算菜单显示位置 - 优先显示在鼠标左上方
|
||||
double left = x - MENU_WIDTH;
|
||||
double top = y - MENU_HEIGHT;
|
||||
|
||||
Console.WriteLine($"初始计算位置 (左上方): Left={left}, Top={top}");
|
||||
|
||||
// 智能位置调整算法
|
||||
var adjustedPosition = CalculateOptimalPosition(x, y, workArea, MENU_WIDTH, MENU_HEIGHT);
|
||||
left = adjustedPosition.X;
|
||||
top = adjustedPosition.Y;
|
||||
|
||||
Console.WriteLine($"智能调整后位置: Left={left}, Top={top}");
|
||||
|
||||
// 最终边界检查(确保完全在工作区域内)
|
||||
left = Math.Max(workArea.Left, Math.Min(left, workArea.Right - MENU_WIDTH));
|
||||
top = Math.Max(workArea.Top, Math.Min(top, workArea.Bottom - MENU_HEIGHT));
|
||||
|
||||
Console.WriteLine($"最终边界检查后位置: Left={left}, Top={top}");
|
||||
|
||||
// 设置窗口位置
|
||||
this.Left = left;
|
||||
this.Top = top;
|
||||
|
||||
// 显示窗口
|
||||
this.Show();
|
||||
this.Activate();
|
||||
this.Focus();
|
||||
|
||||
// 验证实际设置的位置
|
||||
Console.WriteLine($"窗口实际位置: Left={this.Left}, Top={this.Top}");
|
||||
Console.WriteLine($"窗口实际尺寸: Width={this.ActualWidth}, Height={this.ActualHeight}");
|
||||
Console.WriteLine("=== Debug End ===\n");
|
||||
}
|
||||
|
||||
private (double X, double Y) CalculateOptimalPosition(int mouseX, int mouseY,
|
||||
Shell.Utils.TrayIconManager.RECT workArea, double menuWidth, double menuHeight)
|
||||
{
|
||||
double left, top;
|
||||
|
||||
// 定义四个可能的位置:左上、右上、左下、右下
|
||||
var positions = new[]
|
||||
{
|
||||
new
|
||||
{
|
||||
X = (double)(mouseX - menuWidth), Y = (double)(mouseY - menuHeight), Priority = 1, Name = "左上"
|
||||
}, // 左上 (优先)
|
||||
new { X = (double)mouseX, Y = (double)(mouseY - menuHeight), Priority = 2, Name = "右上" }, // 右上
|
||||
new { X = (double)(mouseX - menuWidth), Y = (double)mouseY, Priority = 3, Name = "左下" }, // 左下
|
||||
new { X = (double)mouseX, Y = (double)mouseY, Priority = 4, Name = "右下" } // 右下
|
||||
};
|
||||
|
||||
// 检查每个位置是否完全在工作区域内
|
||||
foreach (var pos in positions.OrderBy(p => p.Priority))
|
||||
{
|
||||
bool fitsHorizontally = pos.X >= workArea.Left && pos.X + menuWidth <= workArea.Right;
|
||||
bool fitsVertically = pos.Y >= workArea.Top && pos.Y + menuHeight <= workArea.Bottom;
|
||||
|
||||
Console.WriteLine(
|
||||
$"检查位置 {pos.Name}: X={pos.X:F1}, Y={pos.Y:F1}, 水平适合={fitsHorizontally}, 垂直适合={fitsVertically}");
|
||||
|
||||
if (fitsHorizontally && fitsVertically)
|
||||
{
|
||||
Console.WriteLine($"选择位置: {pos.Name}");
|
||||
return (pos.X, pos.Y);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有位置完全适合,使用智能调整
|
||||
Console.WriteLine("没有完全适合的位置,使用智能调整");
|
||||
|
||||
// 计算最佳的水平位置
|
||||
if (mouseX - menuWidth >= workArea.Left)
|
||||
{
|
||||
left = mouseX - menuWidth; // 左侧有足够空间
|
||||
}
|
||||
else if (mouseX + menuWidth <= workArea.Right)
|
||||
{
|
||||
left = mouseX; // 右侧有足够空间
|
||||
}
|
||||
else
|
||||
{
|
||||
// 两侧都不够,居中显示或贴边
|
||||
left = Math.Max(workArea.Left, workArea.Right - menuWidth);
|
||||
}
|
||||
|
||||
// 计算最佳的垂直位置
|
||||
if (mouseY - menuHeight >= workArea.Top)
|
||||
{
|
||||
top = mouseY - menuHeight; // 上方有足够空间
|
||||
}
|
||||
else if (mouseY + menuHeight <= workArea.Bottom)
|
||||
{
|
||||
top = mouseY; // 下方有足够空间
|
||||
}
|
||||
else
|
||||
{
|
||||
// 上下都不够,贴顶部或底部
|
||||
top = Math.Max(workArea.Top, workArea.Bottom - menuHeight);
|
||||
}
|
||||
|
||||
Console.WriteLine($"智能调整结果: Left={left:F1}, Top={top:F1}");
|
||||
return (left, top);
|
||||
}
|
||||
|
||||
private System.Windows.DpiScale GetDpiScale()
|
||||
{
|
||||
try
|
||||
{
|
||||
var source = PresentationSource.FromVisual(this);
|
||||
if (source?.CompositionTarget != null)
|
||||
{
|
||||
return VisualTreeHelper.GetDpi(this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"获取DPI缩放失败: {ex.Message}");
|
||||
}
|
||||
|
||||
// 返回默认缩放
|
||||
return new System.Windows.DpiScale(1.0, 1.0);
|
||||
}
|
||||
|
||||
private void ShowMainWindow_Click(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
OnShowMainWindow?.Invoke();
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
private void HideToTray_Click(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
OnHideToTray?.Invoke();
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
private void About_Click(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
System.Windows.MessageBox.Show("这是一个带有系统托盘功能的WPF应用程序。", "关于",
|
||||
System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
private void ExitApplication_Click(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var result = System.Windows.MessageBox.Show("确定要退出程序吗?", "确认退出",
|
||||
System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Question);
|
||||
if (result == System.Windows.MessageBoxResult.Yes)
|
||||
{
|
||||
OnExitApplication?.Invoke();
|
||||
}
|
||||
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
private void Window_Deactivated(object sender, EventArgs e)
|
||||
{
|
||||
// 当窗口失去焦点时自动隐藏
|
||||
this.Hide();
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ using Infrastructure.utils;
|
||||
|
||||
namespace Shell.UserControls;
|
||||
|
||||
public partial class WebPanel : UserControl
|
||||
public partial class WebPanel : System.Windows.Controls.UserControl
|
||||
{
|
||||
public WebPanel()
|
||||
{
|
||||
@@ -87,7 +87,7 @@ public partial class WebPanel : UserControl
|
||||
switch (msg?.Channel)
|
||||
{
|
||||
case "showMessage":
|
||||
MessageBox.Show(msg.Payload?.Content ?? "无内容", msg.Payload?.Title ?? "提示");
|
||||
System.Windows.MessageBox.Show(msg.Payload?.Content ?? "无内容", msg.Payload?.Title ?? "提示");
|
||||
InitWebView1();
|
||||
break;
|
||||
case "GetNetInfo":
|
||||
@@ -175,4 +175,4 @@ public class JsData
|
||||
{
|
||||
return $"Title:{Title}, Content:{Content}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using Shell.UserControls;
|
||||
|
||||
namespace Shell.Utils;
|
||||
|
||||
public class TrayIconManager : IDisposable
|
||||
{
|
||||
private NotifyIcon _notifyIcon;
|
||||
private Window _mainWindow;
|
||||
private TrayMenuWindow _trayMenu;
|
||||
private DispatcherTimer _clickTimer;
|
||||
private bool _isDoubleClick = false;
|
||||
|
||||
// Win32 API 用于获取鼠标位置和显示器信息
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetCursorPos(out POINT lpPoint);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr MonitorFromPoint(POINT pt, uint dwFlags);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
|
||||
|
||||
// 添加DPI相关API
|
||||
[DllImport("user32.dll")]
|
||||
private static extern uint GetDpiForWindow(IntPtr hwnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern uint GetDpiForSystem();
|
||||
|
||||
[DllImport("shcore.dll")]
|
||||
private static extern int GetDpiForMonitor(IntPtr hmonitor, DpiType dpiType, out uint dpiX, out uint dpiY);
|
||||
|
||||
public enum DpiType
|
||||
{
|
||||
Effective = 0,
|
||||
Angular = 1,
|
||||
Raw = 2,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct POINT
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MONITORINFO
|
||||
{
|
||||
public uint cbSize;
|
||||
public RECT rcMonitor;
|
||||
public RECT rcWork;
|
||||
public uint dwFlags;
|
||||
}
|
||||
|
||||
private const uint MONITOR_DEFAULTTONEAREST = 2;
|
||||
|
||||
public TrayIconManager(Window mainWindow)
|
||||
{
|
||||
_mainWindow = mainWindow;
|
||||
InitializeTrayIcon();
|
||||
InitializeClickTimer();
|
||||
}
|
||||
|
||||
private void InitializeTrayIcon()
|
||||
{
|
||||
_notifyIcon = new NotifyIcon
|
||||
{
|
||||
Icon = LoadIcon(),
|
||||
Visible = true,
|
||||
Text = "你的应用程序"
|
||||
};
|
||||
|
||||
_notifyIcon.MouseClick += OnTrayIconClick;
|
||||
_notifyIcon.MouseDoubleClick += OnTrayIconDoubleClick;
|
||||
}
|
||||
|
||||
private void InitializeClickTimer()
|
||||
{
|
||||
_clickTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(300)
|
||||
};
|
||||
_clickTimer.Tick += OnClickTimerTick;
|
||||
}
|
||||
|
||||
private Icon LoadIcon()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Icon("Assets/Icons/app.ico");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return SystemIcons.Application;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTrayIconClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
try
|
||||
{
|
||||
ShowContextMenu();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine(exception);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
_isDoubleClick = false;
|
||||
_clickTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTrayIconDoubleClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
_isDoubleClick = true;
|
||||
_clickTimer.Stop();
|
||||
ShowMainWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClickTimerTick(object sender, EventArgs e)
|
||||
{
|
||||
_clickTimer.Stop();
|
||||
if (!_isDoubleClick)
|
||||
{
|
||||
// 单击逻辑(可选)
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowMainWindow()
|
||||
{
|
||||
if (_mainWindow != null)
|
||||
{
|
||||
_mainWindow.Show();
|
||||
_mainWindow.WindowState = WindowState.Normal;
|
||||
_mainWindow.Activate();
|
||||
_mainWindow.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowContextMenu()
|
||||
{
|
||||
Console.WriteLine("=== TrayIconManager ShowContextMenu ===");
|
||||
|
||||
if (_trayMenu == null)
|
||||
{
|
||||
_trayMenu = new TrayMenuWindow();
|
||||
_trayMenu.OnShowMainWindow += () => ShowMainWindow();
|
||||
_trayMenu.OnExitApplication += () => System.Windows.Application.Current.Shutdown();
|
||||
_trayMenu.OnHideToTray += () => _mainWindow?.Hide();
|
||||
Console.WriteLine("创建新的TrayMenuWindow");
|
||||
}
|
||||
|
||||
// 使用Win32 API获取鼠标位置
|
||||
if (GetCursorPos(out POINT mousePos))
|
||||
{
|
||||
Console.WriteLine($"Win32 API获取鼠标物理位置: X={mousePos.X}, Y={mousePos.Y}");
|
||||
|
||||
// 获取鼠标所在显示器的工作区域和DPI信息
|
||||
var (workArea, dpiScaleX, dpiScaleY) = GetMouseMonitorInfoWithDpi(mousePos);
|
||||
Console.WriteLine(
|
||||
$"显示器工作区域: Left={workArea.Left}, Top={workArea.Top}, Right={workArea.Right}, Bottom={workArea.Bottom}");
|
||||
Console.WriteLine($"DPI缩放比例: ScaleX={dpiScaleX:F2}, ScaleY={dpiScaleY:F2}");
|
||||
|
||||
// 将物理坐标转换为WPF逻辑坐标
|
||||
var logicalMouseX = mousePos.X / dpiScaleX;
|
||||
var logicalMouseY = mousePos.Y / dpiScaleY;
|
||||
|
||||
// 将工作区域也转换为逻辑坐标
|
||||
var logicalWorkArea = new RECT
|
||||
{
|
||||
Left = (int)(workArea.Left / dpiScaleX),
|
||||
Top = (int)(workArea.Top / dpiScaleY),
|
||||
Right = (int)(workArea.Right / dpiScaleX),
|
||||
Bottom = (int)(workArea.Bottom / dpiScaleY)
|
||||
};
|
||||
|
||||
Console.WriteLine($"逻辑鼠标位置: X={logicalMouseX:F1}, Y={logicalMouseY:F1}");
|
||||
Console.WriteLine(
|
||||
$"逻辑工作区域: Left={logicalWorkArea.Left}, Top={logicalWorkArea.Top}, Right={logicalWorkArea.Right}, Bottom={logicalWorkArea.Bottom}");
|
||||
|
||||
_trayMenu.ShowAtWithWorkArea((int)logicalMouseX, (int)logicalMouseY, logicalWorkArea);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("获取鼠标位置失败,使用默认位置");
|
||||
// 如果获取鼠标位置失败,使用托盘图标的估计位置
|
||||
var workArea = SystemParameters.WorkArea;
|
||||
var defaultX = (int)workArea.Right - 50;
|
||||
var defaultY = (int)workArea.Bottom - 50;
|
||||
Console.WriteLine($"使用默认位置: X={defaultX}, Y={defaultY}");
|
||||
_trayMenu.ShowAt(defaultX, defaultY);
|
||||
}
|
||||
|
||||
Console.WriteLine("=== ShowContextMenu End ===\n");
|
||||
}
|
||||
|
||||
private (RECT workArea, double dpiScaleX, double dpiScaleY) GetMouseMonitorInfoWithDpi(POINT mousePos)
|
||||
{
|
||||
// 获取鼠标所在的显示器
|
||||
IntPtr hMonitor = MonitorFromPoint(mousePos, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
// 获取显示器信息
|
||||
MONITORINFO monitorInfo = new MONITORINFO();
|
||||
monitorInfo.cbSize = (uint)Marshal.SizeOf(monitorInfo);
|
||||
|
||||
RECT workArea;
|
||||
double dpiScaleX = 1.0;
|
||||
double dpiScaleY = 1.0;
|
||||
|
||||
if (GetMonitorInfo(hMonitor, ref monitorInfo))
|
||||
{
|
||||
workArea = monitorInfo.rcWork;
|
||||
|
||||
// 获取该显示器的DPI
|
||||
try
|
||||
{
|
||||
if (GetDpiForMonitor(hMonitor, DpiType.Effective, out uint dpiX, out uint dpiY) == 0)
|
||||
{
|
||||
dpiScaleX = dpiX / 96.0; // 96 DPI是标准DPI
|
||||
dpiScaleY = dpiY / 96.0;
|
||||
Console.WriteLine($"显示器DPI: X={dpiX}, Y={dpiY}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果GetDpiForMonitor失败,尝试使用系统DPI
|
||||
var systemDpi = GetDpiForSystem();
|
||||
dpiScaleX = dpiScaleY = systemDpi / 96.0;
|
||||
Console.WriteLine($"使用系统DPI: {systemDpi}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"获取DPI失败: {ex.Message},使用默认缩放");
|
||||
// 作为后备方案,使用WPF的DPI信息
|
||||
var source = PresentationSource.FromVisual(System.Windows.Application.Current.MainWindow);
|
||||
if (source?.CompositionTarget != null)
|
||||
{
|
||||
var matrix = source.CompositionTarget.TransformFromDevice;
|
||||
dpiScaleX = 1.0 / matrix.M11;
|
||||
dpiScaleY = 1.0 / matrix.M22;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果获取失败,返回主显示器的工作区域
|
||||
var wpfWorkArea = SystemParameters.WorkArea;
|
||||
workArea = new RECT
|
||||
{
|
||||
Left = (int)wpfWorkArea.Left,
|
||||
Top = (int)wpfWorkArea.Top,
|
||||
Right = (int)wpfWorkArea.Right,
|
||||
Bottom = (int)wpfWorkArea.Bottom
|
||||
};
|
||||
|
||||
// 使用WPF的DPI信息作为后备
|
||||
var source = PresentationSource.FromVisual(System.Windows.Application.Current.MainWindow);
|
||||
if (source?.CompositionTarget != null)
|
||||
{
|
||||
var matrix = source.CompositionTarget.TransformFromDevice;
|
||||
dpiScaleX = 1.0 / matrix.M11;
|
||||
dpiScaleY = 1.0 / matrix.M22;
|
||||
}
|
||||
}
|
||||
|
||||
return (workArea, dpiScaleX, dpiScaleY);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_notifyIcon?.Dispose();
|
||||
_trayMenu?.Close();
|
||||
_clickTimer?.Stop();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,41 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using Shell.Utils;
|
||||
|
||||
namespace Shell.Views;
|
||||
|
||||
public partial class NetView : Window
|
||||
{
|
||||
private TrayIconManager _trayIconManager;
|
||||
|
||||
public NetView()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeTrayIcon();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeTrayIcon()
|
||||
{
|
||||
_trayIconManager = new TrayIconManager(this);
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
// 阻止窗口关闭,而是隐藏到托盘
|
||||
e.Cancel = true;
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
_trayIconManager?.Dispose();
|
||||
base.OnClosed(e);
|
||||
}
|
||||
|
||||
// 如果你想要真正关闭程序的方法
|
||||
public void ForceClose()
|
||||
{
|
||||
_trayIconManager?.Dispose();
|
||||
System.Windows.Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
/// Windows防火墙策略对象,用于访问防火墙的全局设置和状态
|
||||
/// </summary>
|
||||
private readonly INetFwPolicy2? _fwPolicy;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Windows防火墙规则集合对象,用于管理防火墙规则
|
||||
/// </summary>
|
||||
@@ -73,9 +73,9 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
|
||||
// 获取规则统计信息
|
||||
var allRules = GetAllRules();
|
||||
status.TotalRules = allRules.Count; // 总规则数
|
||||
status.EnabledRules = allRules.Count(r => r.Enabled); // 已启用规则数
|
||||
status.InboundRules = allRules.Count(r => r.Direction == RuleDirection.Inbound); // 入站规则数
|
||||
status.TotalRules = allRules.Count; // 总规则数
|
||||
status.EnabledRules = allRules.Count(r => r.Enabled); // 已启用规则数
|
||||
status.InboundRules = allRules.Count(r => r.Direction == RuleDirection.Inbound); // 入站规则数
|
||||
status.OutboundRules = allRules.Count(r => r.Direction == RuleDirection.Outbound); // 出站规则数
|
||||
|
||||
return status;
|
||||
@@ -164,12 +164,12 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
return new ProfileStatus
|
||||
{
|
||||
Profile = profile,
|
||||
IsEnabled = _fwPolicy.FirewallEnabled[profileType], // 是否启用
|
||||
BlockAllInboundTraffic = _fwPolicy.BlockAllInboundTraffic[profileType], // 是否阻止所有入站流量
|
||||
NotifyOnListen = _fwPolicy.NotificationsDisabled[profileType] == false, // 是否显示通知
|
||||
IsEnabled = _fwPolicy.FirewallEnabled[profileType], // 是否启用
|
||||
BlockAllInboundTraffic = _fwPolicy.BlockAllInboundTraffic[profileType], // 是否阻止所有入站流量
|
||||
NotifyOnListen = _fwPolicy.NotificationsDisabled[profileType] == false, // 是否显示通知
|
||||
UnicastResponsesDisabled = _fwPolicy.UnicastResponsesToMulticastBroadcastDisabled[profileType], // 单播响应设置
|
||||
DefaultInboundAction = (RuleAction)_fwPolicy.DefaultInboundAction[profileType], // 默认入站动作
|
||||
DefaultOutboundAction = (RuleAction)_fwPolicy.DefaultOutboundAction[profileType] // 默认出站动作
|
||||
DefaultInboundAction = (RuleAction)_fwPolicy.DefaultInboundAction[profileType], // 默认入站动作
|
||||
DefaultOutboundAction = (RuleAction)_fwPolicy.DefaultOutboundAction[profileType] // 默认出站动作
|
||||
};
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
if (_fwPolicy == null) return false;
|
||||
|
||||
var profileType = ConvertToNetFwProfile(profile);
|
||||
|
||||
|
||||
// 设置各项配置
|
||||
_fwPolicy.FirewallEnabled[profileType] = status.IsEnabled;
|
||||
_fwPolicy.BlockAllInboundTraffic[profileType] = status.BlockAllInboundTraffic;
|
||||
@@ -194,7 +194,7 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
_fwPolicy.UnicastResponsesToMulticastBroadcastDisabled[profileType] = status.UnicastResponsesDisabled;
|
||||
_fwPolicy.DefaultInboundAction[profileType] = (NET_FW_ACTION_)status.DefaultInboundAction;
|
||||
_fwPolicy.DefaultOutboundAction[profileType] = (NET_FW_ACTION_)status.DefaultOutboundAction;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
@@ -219,7 +219,8 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
// 遍历Windows防火墙中的所有规则并转换为自定义格式
|
||||
foreach (INetFwRule rule in _fwRules)
|
||||
{
|
||||
rules.Add(ConvertToFirewallRule(rule));
|
||||
var convertToFirewallRule = ConvertToFirewallRule(rule);
|
||||
rules.Add(convertToFirewallRule);
|
||||
}
|
||||
|
||||
return rules;
|
||||
@@ -358,22 +359,22 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
if (newRule == null) return false;
|
||||
|
||||
// 设置规则的各项属性
|
||||
newRule.Name = request.Name; // 规则名称
|
||||
newRule.Description = request.Description; // 规则描述
|
||||
newRule.ApplicationName = request.ApplicationName; // 应用程序路径
|
||||
newRule.Name = request.Name; // 规则名称
|
||||
newRule.Description = request.Description; // 规则描述
|
||||
newRule.ApplicationName = request.ApplicationName; // 应用程序路径
|
||||
// 注意:INetFwRule 接口可能没有 ServiceName 属性,这里移除了对它的直接赋值
|
||||
newRule.Protocol = (int)request.Protocol; // 协议类型
|
||||
newRule.LocalPorts = request.LocalPorts; // 本地端口
|
||||
newRule.RemotePorts = request.RemotePorts; // 远程端口
|
||||
newRule.LocalAddresses = request.LocalAddresses; // 本地地址
|
||||
newRule.RemoteAddresses = request.RemoteAddresses; // 远程地址
|
||||
newRule.IcmpTypesAndCodes = request.IcmpTypesAndCodes; // ICMP类型和代码
|
||||
newRule.Direction = (NET_FW_RULE_DIRECTION_)request.Direction; // 流量方向
|
||||
newRule.Enabled = request.Enabled; // 是否启用
|
||||
newRule.Profiles = ConvertToNetFwProfiles(request.Profiles); // 适用的配置文件
|
||||
newRule.Action = (NET_FW_ACTION_)request.Action; // 规则动作
|
||||
newRule.Grouping = request.Grouping; // 规则组
|
||||
newRule.InterfaceTypes = request.InterfaceTypes; // 接口类型
|
||||
newRule.Protocol = (int)request.Protocol; // 协议类型
|
||||
newRule.LocalPorts = request.LocalPorts; // 本地端口
|
||||
newRule.RemotePorts = request.RemotePorts; // 远程端口
|
||||
newRule.LocalAddresses = request.LocalAddresses; // 本地地址
|
||||
newRule.RemoteAddresses = request.RemoteAddresses; // 远程地址
|
||||
newRule.IcmpTypesAndCodes = request.IcmpTypesAndCodes; // ICMP类型和代码
|
||||
newRule.Direction = (NET_FW_RULE_DIRECTION_)request.Direction; // 流量方向
|
||||
newRule.Enabled = request.Enabled; // 是否启用
|
||||
newRule.Profiles = ConvertToNetFwProfiles(request.Profiles); // 适用的配置文件
|
||||
newRule.Action = (NET_FW_ACTION_)request.Action; // 规则动作
|
||||
newRule.Grouping = request.Grouping; // 规则组
|
||||
newRule.InterfaceTypes = request.InterfaceTypes; // 接口类型
|
||||
|
||||
// 设置边缘遍历(用于某些特殊网络场景)
|
||||
if (request.EdgeTraversal)
|
||||
@@ -469,7 +470,7 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
{
|
||||
// 先获取组中的所有规则
|
||||
var rules = GetRulesByGroup(groupName);
|
||||
|
||||
|
||||
// 逐一删除组中的每个规则
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
@@ -620,14 +621,14 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
try
|
||||
{
|
||||
var rules = GetAllRules();
|
||||
|
||||
|
||||
// 配置JSON序列化选项,包括缩进和枚举转换
|
||||
var json = JsonSerializer.Serialize(rules, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
Converters = { new JsonStringEnumConverter() }
|
||||
});
|
||||
|
||||
|
||||
System.IO.File.WriteAllText(filePath, json);
|
||||
return true;
|
||||
}
|
||||
@@ -647,7 +648,7 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
try
|
||||
{
|
||||
var json = System.IO.File.ReadAllText(filePath);
|
||||
|
||||
|
||||
// 反序列化JSON文件中的规则
|
||||
var rules = JsonSerializer.Deserialize<List<FirewallRule>>(json, new JsonSerializerOptions
|
||||
{
|
||||
@@ -700,9 +701,9 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
var rules = GetAllRules();
|
||||
var stats = new FirewallStatistics
|
||||
{
|
||||
TotalRules = rules.Count, // 总规则数
|
||||
EnabledRules = rules.Count(r => r.Enabled), // 已启用规则数
|
||||
DisabledRules = rules.Count(r => !r.Enabled) // 已禁用规则数
|
||||
TotalRules = rules.Count, // 总规则数
|
||||
EnabledRules = rules.Count(r => r.Enabled), // 已启用规则数
|
||||
DisabledRules = rules.Count(r => !r.Enabled) // 已禁用规则数
|
||||
};
|
||||
|
||||
// 按流量方向统计规则数量
|
||||
@@ -795,7 +796,7 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
public bool BlockApplication(string applicationPath)
|
||||
{
|
||||
var fileName = System.IO.Path.GetFileName(applicationPath);
|
||||
|
||||
|
||||
// 创建入站阻止规则
|
||||
var blockInbound = CreateRule(new CreateRuleRequest
|
||||
{
|
||||
@@ -1043,25 +1044,25 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
{
|
||||
return new FirewallRule
|
||||
{
|
||||
Name = rule.Name ?? string.Empty, // 规则名称
|
||||
Description = rule.Description ?? string.Empty, // 规则描述
|
||||
ApplicationName = rule.ApplicationName ?? string.Empty, // 应用程序路径
|
||||
Name = rule.Name ?? string.Empty, // 规则名称
|
||||
Description = rule.Description ?? string.Empty, // 规则描述
|
||||
ApplicationName = rule.ApplicationName ?? string.Empty, // 应用程序路径
|
||||
// ServiceName 在某些版本的 INetFwRule 中可能不存在,使用默认值
|
||||
ServiceName = string.Empty, // 服务名称
|
||||
Protocol = (ProtocolType)rule.Protocol, // 协议类型
|
||||
LocalPorts = rule.LocalPorts ?? string.Empty, // 本地端口
|
||||
RemotePorts = rule.RemotePorts ?? string.Empty, // 远程端口
|
||||
LocalAddresses = rule.LocalAddresses ?? string.Empty, // 本地地址
|
||||
RemoteAddresses = rule.RemoteAddresses ?? string.Empty, // 远程地址
|
||||
IcmpTypesAndCodes = rule.IcmpTypesAndCodes ?? string.Empty, // ICMP类型和代码
|
||||
Direction = (RuleDirection)rule.Direction, // 流量方向
|
||||
Enabled = rule.Enabled, // 是否启用
|
||||
Profiles = ConvertFromNetFwProfiles(rule.Profiles), // 适用的配置文件
|
||||
EdgeTraversal = rule.EdgeTraversal, // 边缘遍历设置
|
||||
Action = (RuleAction)rule.Action, // 规则动作
|
||||
Grouping = rule.Grouping ?? string.Empty, // 规则组
|
||||
InterfaceTypes = rule.InterfaceTypes ?? string.Empty, // 接口类型
|
||||
Interfaces = ParseInterfaces(rule.Interfaces) // 接口列表
|
||||
ServiceName = string.Empty, // 服务名称
|
||||
Protocol = (ProtocolType)rule.Protocol, // 协议类型
|
||||
LocalPorts = rule.LocalPorts ?? string.Empty, // 本地端口
|
||||
RemotePorts = rule.RemotePorts ?? string.Empty, // 远程端口
|
||||
LocalAddresses = rule.LocalAddresses ?? string.Empty, // 本地地址
|
||||
RemoteAddresses = rule.RemoteAddresses ?? string.Empty, // 远程地址
|
||||
IcmpTypesAndCodes = rule.IcmpTypesAndCodes ?? string.Empty, // ICMP类型和代码
|
||||
Direction = (RuleDirection)rule.Direction, // 流量方向
|
||||
Enabled = rule.Enabled, // 是否启用
|
||||
Profiles = ConvertFromNetFwProfiles(rule.Profiles), // 适用的配置文件
|
||||
EdgeTraversal = rule.EdgeTraversal, // 边缘遍历设置
|
||||
Action = (RuleAction)rule.Action, // 规则动作
|
||||
Grouping = rule.Grouping ?? string.Empty, // 规则组
|
||||
InterfaceTypes = rule.InterfaceTypes ?? string.Empty, // 接口类型
|
||||
Interfaces = ParseInterfaces(rule.Interfaces) // 接口列表
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1137,4 +1138,4 @@ public class WindowsFirewallApi : IFirewallApi
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user