2023年6月2日金曜日

Windows hosts ファイルを編集して名前解決させる。

hosts

Virtual Machine で開発することが圧倒的に多くなってきましたね。
本番環境と開発環境を分けるためにドメインの名前解決を一時的に変更することも多々あります。
そこで必要になるのが hosts の編集です。

hosts を編集して名前解決させるには

これが、なかなかめんどくさいw
1.メモ帳を管理者モードで起動
2.ファイルを開くで、右下のフィルタを「すべてのファイル」に変更。
3.C:\Windows\System32\drivers\etc\hosts を開いて編集。
4.保存。
5.コマンドプロンプトを開いて
6.C:\> ipconfig /flushdns

一日一回とかならまだいいけど、数回実施するとなるとめんどくさいね。
ということで、プログラム書いてみましたw

HostsEditor

今回は、Visual Studio 2022 Comunity の C# Windows Form .NET プロジェクトを作成しました。
Form1 には、保存終了用のツールボタンと、全画面に Dock した TextBox を配置します
TextBox のプロパティは、Multiline=true, MaxLength を大きめに。font も大きめに、程度かな。
Name は editText と付けておきました。

Form1.cs

プログラムは、こんな感じです。
hosts ファイルの位置を保持
全行を読み込んで TextBox に入れて編集可能にする
保存ボタンが押されたら、保存して、CMD.exe で ipconfig /flushdns を実行。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace HostsEditor
{
    public partial class Form1 : Form
    {
        internal string HostsFileName { get; set; }
        public Form1()
        {
            InitializeComponent();
        }

        //初期表示
        private void Form1_Load(object sender, EventArgs e)
        {
            // ファイル名
            string system_folder = Environment.GetFolderPath(Environment.SpecialFolder.System);
            string hosts_path = Path.Combine(system_folder, "drivers", "etc");
            HostsFileName = Path.Combine(hosts_path, "hosts");

            System.IO.FileInfo fi = new System.IO.FileInfo(HostsFileName);
            if(4194304 < fi.Length)
            {
                MessageBox.Show("hosts ファイルが大きすぎます。他の手段で編集してください。",
                    "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                Close();
            }
            // ファイルを 65,536 byte まで読み込む
            string[] lines = File.ReadAllLines(HostsFileName);
            string text = String.Join("\r\n", lines);
            editText.Text = text;
            // 全選択を解除
            editText.SelectionStart = 0;
        }

        private void closeClick(object sender, EventArgs e)
        {
            try
            {
                // 保存
                string text = editText.Text;
                using (StreamWriter streamWriter = new StreamWriter(HostsFileName))
                {
                    // Writeメソッドで文字列データを書き込む
                    streamWriter.Write(text);
                    // StreamWriterオブジェクトを閉じる
                    streamWriter.Close();
                }
                // ipconfig /flushdns を実行。完了まで待つ。
                System.Diagnostics.Process process = new System.Diagnostics.Process();
                //ComSpec(cmd.exe)のパスを取得して、FileNameプロパティに指定
                process.StartInfo.FileName = System.Environment.GetEnvironmentVariable("ComSpec");
                //出力を読み取れるようにする
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardInput = false;
                //ウィンドウを表示しないようにする
                process.StartInfo.CreateNoWindow = true;
                //コマンドラインを指定("/c"は実行後閉じるために必要)
                process.StartInfo.Arguments = @"/c ipconfig /flushdns";
                //起動
                process.Start();
                //(親プロセス、子プロセスでブロック防止のため)
                process.WaitForExit();
                process.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            // 画面を閉じる
            Close();
        }
    }
}

管理者として起動

プログラムを管理者として起動する必要があるので、Program.cs を編集します。
Main部分に以下の内容を追記します。

        static void Main(string[] args)
        {

            // 管理者権限に昇格させて自分自身を起動する
#if (!DEBUG)
            Thread.GetDomain().SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
            var pri = (WindowsPrincipal)Thread.CurrentPrincipal;
            //管理者権限以外での起動なら, 別プロセスで本アプリを起動する
            if (!pri.IsInRole(WindowsBuiltInRole.Administrator))
            {
                var proc = new ProcessStartInfo()
                {
                    WorkingDirectory = Environment.CurrentDirectory,
                    FileName = Assembly.GetEntryAssembly().Location,
                    Verb = "RunAs"
                };

                if (args.Length >= 1)
                    proc.Arguments = string.Join(" ", args);

                //別プロセスで本アプリを起動する
                Process.Start(proc);

                //現在プロセス終了
                return;
            }
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
#endif

まとめ

DOBON.NET さんの記事を参照しました。
デバッグ時は、VisualStudio を管理者モードで起動する必要があります。
わりと、楽になりましたw
めでたしめでたし。