主要功能
1. hosts文件管理
- 自动检测和创建: 检查hosts文件是否存在,不存在时自动创建
- 备份机制: 备份现有hosts文件并保留时间戳
- 条目过滤: 保留非PDC条目,移除旧的PDC条目
- 新条目添加: 添加新的PDC条目
10.21.129.2 pdc.chana.com
2. 权限提升处理
- 管理员权限: 通过Ctrl+Shift+Enter以管理员身份运行CMD
- 关闭UAC: 通过注册表修改临时禁用UAC
- 系统目录访问: 通过键盘操作Hosts文件系统不会阻止,杀毒软件一般也不会阻止。但是powertoy和UsbEAmHostsEditor对hosts的编辑杀软和系统也不会阻止,不清楚具体实现方法。
3. 用户界面控制
- 控制台管理: 动态显示/隐藏控制台窗口
- 窗口定位: 将CMD窗口定位到屏幕右下角
- 输入法控制: 强制切换为英文输入法避免编码问题
- 焦点管理: 确保正确的窗口获得焦点
核心原理
Windows API集成
// 控制台管理
[DllImport("kernel32.dll")]
private static extern bool AllocConsole();
// 窗口管理
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
// 系统信息获取
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(int nIndex);
自动化流程
- 初始化阶段
- 权限准备阶段
- 禁用UAC(用户账户控制)
- 切换英文输入法
- 以管理员权限启动CMD
- 文件处理阶段
- 备份现有文件
- 过滤保留非PDC条目
- 清空并重建hosts文件
- 添加新PDC条目
- 清理阶段
窗口管理流程
- 检查控制台是否存在
↓
- 不存在则创建并初始化
↓
- 显示控制台窗口
↓
- 强制获得焦点
↓
- 执行操作期间管理CMD窗口
↓
- 操作完成后隐藏控制台
焦点管理
private void ForceForegroundWindow(IntPtr hWnd)
{
// 通过线程附加确保窗口能够获得焦点
AttachThreadInput(foregroundThread, currentThread, true);
SetForegroundWindow(hWnd);
AttachThreadInput(foregroundThread, currentThread, false);
}
控制台窗口管理
private void ShowConsoleAndEnsureFocus()
{
_consoleHandle = GetConsoleWindow();
if (_consoleHandle == IntPtr.Zero)
{
AllocConsole(); // 创建控制台
_consoleHandle = GetConsoleWindow();
// 设置编码和输出流
Console.OutputEncoding = System.Text.Encoding.UTF8;
// ... 其他初始化 ...
}
ShowWindow(_consoleHandle, SW_SHOW); // 显示窗口
Console.Title = "HOSTS文件编辑器";
// ... 界面设置 ...
// 关键:确保控制台获得焦点
ForceForegroundWindow(_consoleHandle);
Thread.Sleep(1500);
}
private void HideConsole()
{
if (_consoleHandle != IntPtr.Zero)
{
ShowWindow(_consoleHandle, SW_HIDE); // 隐藏窗口
}
}
CMD自动化
// 模拟键盘输入执行命令
_inputSimulator.Keyboard.TextEntry("cmd");
_inputSimulator.Keyboard.ModifiedKeyStroke(
new[] { VirtualKeyCode.CONTROL, VirtualKeyCode.SHIFT },
VirtualKeyCode.RETURN);
CMD窗口定位
private void SetCmdWindowPosition()
{
try
{
Thread.Sleep(1500);
IntPtr cmdWindow = GetForegroundWindow();
if (cmdWindow != IntPtr.Zero)
{
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
// 计算右下角位置
int windowWidth = 800;
int windowHeight = 600;
int posX = screenWidth - windowWidth - 50;
int posY = screenHeight - windowHeight - 50;
SetWindowPos(cmdWindow, IntPtr.Zero, posX, posY, windowWidth, windowHeight, SWP_NOZORDER);
// 确保CMD窗口保持焦点
ForceForegroundWindow(cmdWindow);
Thread.Sleep(1000);
}
}
catch (Exception ex)
{
Console.WriteLine($"[警告] 设置窗口位置失败: {ex.Message}");
}
}
焦点强制管理
private void ForceForegroundWindow(IntPtr hWnd)
{
uint foregroundThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint currentThread = (uint)AppDomain.GetCurrentThreadId();
if (foregroundThread != currentThread)
{
AttachThreadInput(foregroundThread, currentThread, true);
SetForegroundWindow(hWnd);
AttachThreadInput(foregroundThread, currentThread, false);
}
else
{
SetForegroundWindow(hWnd);
}
Thread.Sleep(800); // 等待焦点稳定
}
文件处理策略
- 使用临时文件存储非PDC条目
- 通过CMD命令操作避免权限问题
- 使用PowerShell确保中文路径支持
在按钮中使用
//
using HostsFileEditor;
// 按钮事件
HostsEditor editor = new HostsEditor();
editor.EditHostsFile();
源码
using System;
using System.Threading;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using WindowsInput;
using WindowsInput.Native;
using Microsoft.Win32;
namespace HostsFileEditor
{
public class HostsEditor
{
// Windows API 导入
[DllImport("kernel32.dll")]
private static extern bool AllocConsole();
[DllImport("kernel32.dll")]
private static extern bool FreeConsole();
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(int nIndex);
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
private const int SW_HIDE = 0;
private const int SW_SHOW = 5;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOZORDER = 0x0004;
private const int SM_CXSCREEN = 0;
private const int SM_CYSCREEN = 1;
private readonly InputSimulator _inputSimulator;
private readonly string _hostsFilePath;
private readonly string _hostsDirectory;
private readonly string _tempFilePath;
private readonly List<string> _operationLog;
private IntPtr _consoleHandle;
public HostsEditor()
{
_inputSimulator = new InputSimulator();
_hostsFilePath = @"C:\Windows\System32\drivers\etc\hosts";
_hostsDirectory = @"C:\Windows\System32\drivers\etc";
_tempFilePath = @"C:\Windows\System32\drivers\etc\hosts_backup.txt";
_operationLog = new List<string>();
}
public void EditHostsFile()
{
try
{
// 显示控制台并确保获得焦点
ShowConsoleAndEnsureFocus();
Console.WriteLine("[信息] 开始处理hosts文件...");
// 第一步:检查并创建hosts文件(如果需要)
bool fileExisted = CheckAndCreateHostsFile();
// 如果文件原本就存在,才需要后续的编辑步骤
if (fileExisted)
{
Console.WriteLine("[信息] 检测到现有hosts文件,执行编辑流程...");
DisableUAC();
ForceEnglishInputMethod();
// 备份现有hosts文件
BackupHostsFile();
List<string> nonPdcEntries = ReadAndBackupNonPdcEntries();
OpenCmdAndEditHosts(nonPdcEntries);
}
else
{
Console.WriteLine("[信息] 已创建新的hosts文件,包含PDC条目,无需后续编辑");
_operationLog.Add("已创建新的hosts文件并添加PDC条目");
}
// 输出详细操作结果
Console.WriteLine("\n=== 操作完成 ===");
foreach (var log in _operationLog)
{
Console.WriteLine($"[成功] {log}");
}
// 完成后等待用户按键再关闭控制台
Console.WriteLine("\n按任意键关闭控制台...");
Console.ReadKey();
HideConsole();
}
catch (Exception ex)
{
Console.WriteLine($"\n[失败] 操作失败: {ex.Message}");
Console.WriteLine("按任意键关闭控制台...");
Console.ReadKey();
HideConsole();
throw;
}
}
private void ShowConsoleAndEnsureFocus()
{
_consoleHandle = GetConsoleWindow();
if (_consoleHandle == IntPtr.Zero)
{
AllocConsole();
_consoleHandle = GetConsoleWindow();
// 设置控制台编码为UTF-8
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.InputEncoding = System.Text.Encoding.UTF8;
// 重定向标准输出到控制台
var standardOutput = new StreamWriter(Console.OpenStandardOutput());
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
// 重定向标准错误到控制台
var standardError = new StreamWriter(Console.OpenStandardError());
standardError.AutoFlush = true;
Console.SetError(standardError);
}
ShowWindow(_consoleHandle, SW_SHOW);
Console.Title = "HOSTS文件编辑器";
Console.ForegroundColor = ConsoleColor.White;
Console.BackgroundColor = ConsoleColor.Black;
Console.Clear();
// 关键修复:确保控制台获得焦点
ForceForegroundWindow(_consoleHandle);
// 等待控制台完全激活
Thread.Sleep(1500);
// 立即输出测试信息
Console.WriteLine("=== HOSTS文件编辑器控制台 ===");
Console.WriteLine("控制台初始化完成,开始执行...\n");
}
private void HideConsole()
{
if (_consoleHandle != IntPtr.Zero)
{
ShowWindow(_consoleHandle, SW_HIDE);
}
}
// 修复:使用 .NET 内置的 GetCurrentThreadId
private void ForceForegroundWindow(IntPtr hWnd)
{
uint foregroundThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint currentThread = (uint)AppDomain.GetCurrentThreadId(); // 使用 .NET 内置方法
if (foregroundThread != currentThread)
{
AttachThreadInput(foregroundThread, currentThread, true);
SetForegroundWindow(hWnd);
AttachThreadInput(foregroundThread, currentThread, false);
}
else
{
SetForegroundWindow(hWnd);
}
// 额外等待确保焦点稳定
Thread.Sleep(800);
}
private bool CheckAndCreateHostsFile()
{
try
{
if (File.Exists(_hostsFilePath))
{
Console.WriteLine("[信息] 检测到hosts文件,继续执行编辑流程...");
return true;
}
Console.WriteLine("[信息] hosts文件不存在,将通过CMD方式创建...");
bool created = CreateHostsFileViaCmd();
if (created)
{
Console.WriteLine("[成功] hosts文件创建完成,包含PDC条目");
return false;
}
else
{
throw new Exception("hosts文件创建失败");
}
}
catch (Exception ex)
{
Console.WriteLine($"[错误] 检查hosts文件失败: {ex.Message}");
throw;
}
}
private bool CreateHostsFileViaCmd()
{
try
{
Console.WriteLine("[执行] 正在以管理员权限打开CMD创建hosts文件...");
Thread.Sleep(1500); // 增加等待时间
// 确保控制台焦点
ForceForegroundWindow(_consoleHandle);
Thread.Sleep(800);
// 以管理员权限打开CMD
_inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_R);
Thread.Sleep(500); // 增加等待时间
_inputSimulator.Keyboard.TextEntry("cmd");
Thread.Sleep(500);
_inputSimulator.Keyboard.ModifiedKeyStroke(
new[] { VirtualKeyCode.CONTROL, VirtualKeyCode.SHIFT },
VirtualKeyCode.RETURN);
Thread.Sleep(2000); // 重要:等待UAC对话框和处理
// 设置CMD窗口位置到右下角
SetCmdWindowPosition();
// 等待CMD窗口完全激活
Thread.Sleep(1500);
Console.WriteLine("[信息] CMD已以管理员权限打开,开始创建hosts文件...");
// 切换到hosts目录
_inputSimulator.Keyboard.TextEntry($"cd /d \"{_hostsDirectory}\"");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(1500);
// 使用chcp命令设置控制台编码为UTF-8
ExecuteCmdCommand("设置UTF-8编码", "chcp 65001");
// 创建包含PDC条目的hosts文件 - 使用支持中文的编码方式
ExecuteCmdCommand("创建hosts文件头", "echo # Hosts文件 > hosts");
ExecuteCmdCommand("添加本地主机条目", "echo 127.0.0.1 localhost >> hosts");
ExecuteCmdCommand("添加IPv6本地主机条目", "echo ::1 localhost >> hosts");
ExecuteCmdCommand("添加注释", "echo # PDC条目 >> hosts");
ExecuteCmdCommand("添加PDC条目", "echo 10.21.129.2 pdc.chana.com >> hosts");
ExecuteCmdCommand("添加空行", "echo. >> hosts");
// 验证文件
_inputSimulator.Keyboard.TextEntry("dir hosts");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(1500);
_inputSimulator.Keyboard.TextEntry("type hosts");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(1500);
// 关闭CMD
_inputSimulator.Keyboard.TextEntry("exit");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(1500);
return File.Exists(_hostsFilePath);
}
catch (Exception ex)
{
Console.WriteLine($"[错误] 通过CMD创建文件失败: {ex.Message}");
return false;
}
}
private void SetCmdWindowPosition()
{
try
{
Thread.Sleep(1500); // 增加等待时间,确保窗口完全打开
IntPtr cmdWindow = GetForegroundWindow();
if (cmdWindow != IntPtr.Zero)
{
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
// 设置窗口大小和位置(右下角)
int windowWidth = 800;
int windowHeight = 600;
int posX = screenWidth - windowWidth - 50; // 距离右边50像素
int posY = screenHeight - windowHeight - 50; // 距离底部50像素
SetWindowPos(cmdWindow, IntPtr.Zero, posX, posY, windowWidth, windowHeight, SWP_NOZORDER);
Console.WriteLine($"[信息] CMD窗口已移动到右下角位置: ({posX}, {posY})");
// 确保CMD窗口保持焦点
ForceForegroundWindow(cmdWindow);
Thread.Sleep(1000);
}
}
catch (Exception ex)
{
Console.WriteLine($"[警告] 设置窗口位置失败: {ex.Message}");
}
}
private void ExecuteCmdCommand(string stepName, string command)
{
Console.WriteLine($"[执行] {stepName}...");
// 确保CMD窗口有焦点
IntPtr cmdWindow = GetForegroundWindow();
if (cmdWindow != _consoleHandle) // 如果不是控制台窗口,说明是CMD窗口
{
ForceForegroundWindow(cmdWindow);
Thread.Sleep(500);
}
_inputSimulator.Keyboard.TextEntry(command);
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(1200); // 增加等待时间
}
private void BackupHostsFile()
{
try
{
if (File.Exists(_hostsFilePath))
{
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
string backupFileName = $"hosts_{timestamp}.txt";
string backupFilePath = Path.Combine(_hostsDirectory, backupFileName);
File.Copy(_hostsFilePath, backupFilePath, true);
_operationLog.Add($"hosts文件已备份为: {backupFileName}");
Console.WriteLine($"[完成] hosts文件已备份: {backupFileName}");
}
}
catch (Exception ex)
{
Console.WriteLine($"[警告] 备份hosts文件失败: {ex.Message}");
}
}
private void DisableUAC()
{
try
{
Console.WriteLine("[执行] 正在关闭UAC...");
string registryPath = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System";
SetUACLevel(registryPath, 0);
_operationLog.Add("UAC已成功关闭");
Console.WriteLine("[完成] UAC关闭完成");
}
catch (Exception ex)
{
Console.WriteLine($"[错误] 关闭UAC失败: {ex.Message}");
throw;
}
}
private void SetUACLevel(string registryPath, int uacLevel)
{
try
{
Registry.SetValue(registryPath, "ConsentPromptBehaviorAdmin", uacLevel, RegistryValueKind.DWord);
Registry.SetValue(registryPath, "EnableLUA", uacLevel == 0 ? 0 : 1, RegistryValueKind.DWord);
Registry.SetValue(registryPath, "PromptOnSecureDesktop", uacLevel == 0 ? 0 : 1, RegistryValueKind.DWord);
}
catch (Exception ex)
{
Console.WriteLine($"[错误] 设置UAC等级失败: {ex.Message}");
throw;
}
}
private void ForceEnglishInputMethod()
{
try
{
Console.WriteLine("[执行] 正在切换输入法为英文模式...");
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
SwitchToEnglishInputMethod();
Thread.Sleep(800);
_operationLog.Add("输入法已切换为英文模式");
Console.WriteLine("[完成] 输入法切换完成");
}
catch (Exception ex)
{
Console.WriteLine($"[警告] 输入法切换警告: {ex.Message}");
}
}
private void SwitchToEnglishInputMethod()
{
try
{
_inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.SPACE);
Thread.Sleep(800);
_inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.SPACE);
Thread.Sleep(800);
}
catch (Exception ex)
{
Console.WriteLine($"[错误] 输入法切换失败: {ex.Message}");
}
}
private List<string> ReadAndBackupNonPdcEntries()
{
var nonPdcEntries = new List<string>();
try
{
Console.WriteLine("[执行] 正在读取和备份hosts文件...");
string[] allLines = File.ReadAllLines(_hostsFilePath);
int pdcCount = 0;
int validEntriesCount = 0;
foreach (string line in allLines)
{
string trimmedLine = line.Trim();
if (!string.IsNullOrWhiteSpace(trimmedLine) &&
!trimmedLine.Contains("pdc.chana.com"))
{
nonPdcEntries.Add(line);
validEntriesCount++;
}
else if (trimmedLine.Contains("pdc.chana.com") && !trimmedLine.StartsWith("#"))
{
pdcCount++;
}
}
if (nonPdcEntries.Count > 0)
{
File.WriteAllLines(_tempFilePath, nonPdcEntries);
Console.WriteLine($"[信息] 已创建临时备份文件: {_tempFilePath}");
}
Console.WriteLine($"[信息] 过滤 {pdcCount} 个PDC条目,保留 {nonPdcEntries.Count} 个有效条目");
_operationLog.Add($"已备份 {validEntriesCount} 个非PDC条目,移除 {pdcCount} 个旧PDC条目");
Console.WriteLine("[完成] 文件读取备份完成");
}
catch (Exception ex)
{
Console.WriteLine($"[错误] 读取和备份hosts文件失败: {ex.Message}");
throw;
}
return nonPdcEntries;
}
private void OpenCmdAndEditHosts(List<string> nonPdcEntries)
{
try
{
Console.WriteLine("\n[执行] 正在以管理员权限打开CMD进行编辑...");
// 确保控制台有焦点
ForceForegroundWindow(_consoleHandle);
Thread.Sleep(1000);
_inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_R);
Thread.Sleep(800);
_inputSimulator.Keyboard.TextEntry("cmd");
Thread.Sleep(800);
_inputSimulator.Keyboard.ModifiedKeyStroke(
new[] { VirtualKeyCode.CONTROL, VirtualKeyCode.SHIFT },
VirtualKeyCode.RETURN);
Thread.Sleep(2500); // 重要:等待UAC对话框
// 设置CMD窗口位置到右下角
SetCmdWindowPosition();
_operationLog.Add("已以管理员权限打开CMD");
Console.WriteLine("[完成] CMD已打开");
// 执行各个步骤并实时反馈
ExecuteCmdStep("清空hosts文件", () => ClearHostsFile());
if (nonPdcEntries.Count > 0)
{
ExecuteCmdStep("恢复非PDC条目", () => RestoreNonPdcEntries());
}
ExecuteCmdStep("添加新PDC条目", () => AddNewPdcEntry());
ExecuteCmdStep("验证修改结果", () => VerifyFinalResult());
ExecuteCmdStep("清理临时文件", () => CleanupTempFile());
Thread.Sleep(1500);
_inputSimulator.Keyboard.TextEntry("exit");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
_operationLog.Add("CMD窗口已关闭");
Console.WriteLine("[完成] CMD操作完成");
}
catch (Exception ex)
{
Console.WriteLine($"[错误] CMD操作失败: {ex.Message}");
throw;
}
}
private void ExecuteCmdStep(string stepName, Action action)
{
Console.WriteLine($"[执行] {stepName}...");
// 确保CMD窗口有焦点
IntPtr cmdWindow = GetForegroundWindow();
if (cmdWindow != _consoleHandle)
{
ForceForegroundWindow(cmdWindow);
Thread.Sleep(800);
}
action();
Thread.Sleep(1500);
Console.WriteLine($"[完成] {stepName}");
}
private void ClearHostsFile()
{
_inputSimulator.Keyboard.TextEntry($"echo. > \"{_hostsFilePath}\"");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(1500);
_operationLog.Add("hosts文件已清空");
}
private void RestoreNonPdcEntries()
{
_inputSimulator.Keyboard.TextEntry($"type \"{_tempFilePath}\" >> \"{_hostsFilePath}\"");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(2500);
_operationLog.Add("非PDC条目已恢复");
}
private void AddNewPdcEntry()
{
Thread.Sleep(1500);
_inputSimulator.Keyboard.TextEntry($"echo. >> \"{_hostsFilePath}\"");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(1500);
string psCommand = $"Add-Content -Path '{_hostsFilePath}' -Value '10.21.129.2 pdc.chana.com'";
_inputSimulator.Keyboard.TextEntry($"powershell -Command \"{psCommand}\"");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(2000);
_operationLog.Add("新PDC条目已添加: 10.21.129.2 pdc.chana.com");
}
private void VerifyFinalResult()
{
_inputSimulator.Keyboard.TextEntry($"type \"{_hostsFilePath}\" | findstr \"pdc.chana.com\"");
_inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
Thread.Sleep(1500);
_operationLog.Add("hosts文件修改已验证");
}
private void CleanupTempFile()
{
try
{
if (File.Exists(_tempFilePath))
{
File.Delete(_tempFilePath);
_operationLog.Add("临时备份文件已清理");
}
}
catch (Exception ex)
{
Console.WriteLine($"[警告] 清理临时文件失败: {ex.Message}");
}
}
}
}