2015年11月27日金曜日

ProxySwitcher ver.1.0.0

さて、先日公開しましたSSIDProxy ver.1.1.1ですが、実はこっそりプロキシ設定機能の分離を行っておりました。ProxySwitcher.dllっていう新しいDLLが付属するようになったことが勘の良い方は気づいたかもしれません。
なぜ分離したかと言いますと、まあ、プログラムのモジュール化どうこうみたいな話はとりあえず置いておいて、私以外の他人がこれを直接いじれるようにするためです。 先日、ネットサーフィンと言いますか、いわゆるエゴサをしていたところ、VB.NETでプロキシ設定をいじることに苦労されている方がいるのを見かけました。私もこちらの記事で書いたように、一生懸命調べ、レジストリを解析し、やっとC#で設定できるようにこぎつけた経緯があり、この成果を多くの方に使ってもらえるよう、レジストリのデータ構造だけでなくやっぱりライブラリとして公開しようと思い至りました。

というわけで、SSIDProxyに組み込んでいたプロキシ切り替え機能の部分を抽出し、ライブラリとしました。それがProxySwitcherです。
(ちなみに、先日お話をしましたレジストリの変更通知を吐くライブラリもこれに組み込まれています。レジストリの変更通知だけを使いたい方もこのライブラリをどうぞ)

プロキシ設定の仕組み

復習ですが、Windowsのプロキシ設定にかかわるレジストリの項目は下記のようになっています。

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
┣Connections
┃┖DefaultConnectionSettings
┠AutoConfigURL
┠ProxyEnable
┠ProxyServer
┖ProxyOverride

システムはこのうちのDefaultConnectionSettingsに格納されているバイナリデータのみを読み込み、それをプロキシ設定として扱うようになっているようです。しかし、バイナリデータだけでは人間には中身がよくわからないからか、Internett Settings直下の各値にも同じデータを格納してくれるので、これを読み込むことで現在の設定を知ることも可能です。しかし、これはあくまでもダミーで、これを書き換えたところでシステムはそれをプロキシ設定として認識されないことに注意してください。
すなわち、プロキシ設定の読み出しにはDefaultConnectionSettingsを解読するのが素直で、書き込みの時にはDefaultConnectionSettingsとProxyEnableなどの値に適切な値を書き込む必要があるといえます。

ProxySwitcherの使い方

SystemLanSettingsクラス

上記のようなプロキシ設定を行うクラスがSystemLanSettingsクラスです。このクラスは以下のプロパティを持っています。
  • AutomaticallyDetectSettings
  • UseScript
  • ScriptAddress
  • UseProxy
  • Proxy
  • ProxyOverride
これらのプロパティを読み込み、書き込みをすることでシステムのプロキシ設定を読み込み、書き込みすることができます。また、このクラスはレジストリの変更を監視し、プロキシ設定が変化したらそれを通知する機能が付いています。その通知はINotifyPropertyChangedインターフェースによるプロパティ変更通知の実装で実現されているので、変更されたプロキシ設定に対応するプロパティの変更通知として飛んできます。また、レジストリ監視はWin32APIを使用しており、終了時に各種ハンドルを解放しなければならないので、IDisposableインターフェースを実装しております。インスタンスが不必要になったときはDisposeメソッドを呼び出す必要があります
多くのプロパティはstring型かbool型なのでわかりやすいかと思います。しかし、ProxyOverrideはプロキシの不使用をするアドレスを列挙したList<string>型になっているので注意してください。ローカルアドレスにもプロキシを使用しない場合は"<local>"というテキストをそのリストに含ませる必要があります。また、ProxyプロパティはProxySettings型になっております。

ProxySettingsクラス

プロキシ設定を保持するためのクラスです。WindowsはHTTP、HTTPS、FTP、Socksの4種類のプロトコルに対して個別にプロキシサーバーを設定することができます(使ったことないですが)。なので、ProxySettingsクラスはそれに合わせて
  • HttpProxy
  • HttpsProxy
  • FtpProxy
  • SocksProxy
の4つのプロパティを持っており、それぞれの値を設定できます。
このクラスは初期化時以外では値を書き換えることができない(immutableな)設計がされています。プロキシを設定した場合は適当に値を書き換えた上で新しいインスタンスを作ってあげてください。
ちなみに、コンストラクタのオーバーロードがいくつかありますが、そのうちでもstring型のテキストを受け取るものは、レジストリのProxyServerの値をそのまま受け取ってインスタンス化できるものになっています。また、ProxySettingsのインスタンスをToStringするとそのProxyServerのレジストリ値に書き込めるタイプのフォーマットになります。
なお、このクラスで扱われるそれぞれのプロキシ設定はProxy型になっています。

Proxyクラス

これはサーバーのアドレスとポートの2つの値を保持するためだけのクラスです。ProxySettingsクラスと同様にimmutableな設計をしています。string1つを受け取るコンストラクタは「URL:ポート番号」の書式のテキストを受け付けます。

LanSettingsクラス

今まではシステムのLAN設定を読み書きするためのクラスと、そのクラスに付随したクラスの説明をしましたが、単にLAN設定を保持するためのLanSettingsクラスもあります。このクラスのプロパティを読み書きしてもシステムのLAN設定が変化することはありませんが、SystemLanSettings.ToData()やSystemLanSettings.FromData()というstaticメソッドを介してシステムのLAN設定とLanSettingsインスタンスを相互変換できます。この場合、SystemLanSettingsクラスのインスタンスを作るのに比べてレジストリ監視に伴うオーバーヘッドを減らせますし、Dispose()メソッドを呼ぶ必要も無いので扱いやすいかと思います。

サンプルコード

static void Main(string[] args)
{
    LanSettings stg = SystemLanSettings.ToData();
    Console.WriteLine(stg);

    using(var sysstg = new SystemLanSettings()) {
        sysstg.PropertyChanged += (s, e) => Console.WriteLine($"\"{e.PropertyName}\" has changed.");

        Console.WriteLine("Watching LAN Settings...");
        Console.ReadLine();
    }

    Console.WriteLine("Stop Watching.");
    Console.WriteLine("Press Enter to exit...");
    Console.ReadLine();
}

このプログラムを実行するとこんな感じになります。


最初に現在の設定を表示しております。そのあとにインターネットオプションからいくらかプロキシ設定をいじってみたところ、ちゃんとレジストリ変更を認識して画面に表示してくれています。最後にEnterを押せば監視を終了してくれます。

おまけ:レジストリ監視

このライブラリはレジストリ監視機能を含んでいます。ProxySwitcher.Registry.Watcher名前空間内のRegistryWatcherがそれです。面倒くさいんでサンプルプログラムで使い方は察してください。

static void Main(string[] args)
{
    using(var watcher = new RegistryWatcher(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings")) {
        watcher.ValueChanged += (s, e) => {
            foreach(var info in e.ChangeInfo)
                Console.WriteLine(info);
        };
        watcher.SubKeyChanged += (s, e) => {
            foreach(var key in e.CreatedKeyNames)
                Console.WriteLine($"\"{key}\" has created.");
            foreach(var key in e.DeletedKeyNames)
                Console.WriteLine($"\"{key}\" has deleted.");
        };

        Console.WriteLine("Watching LAN Settings...");
        Console.ReadLine();
    }

    Console.WriteLine("Stop Watching.");
    Console.WriteLine("Press Enter to exit...");
    Console.ReadLine();
}

実行結果はこんな感じになります。


このクラスでは指定したキーの直下にある値の変更、指定したキーの直下へのキーの作成、削除を認識できます。これをうまく使って上記のSystemLanSettingsクラスはプロキシ設定の変更通知を行っています。ちゃんとそのキー下の値やキー名を記憶しておいて、変更があった時に素の差分を通知してくれるようになっています。

免責事項

このソフトウェアを使用することによって発生したいかなるトラブル(データ喪失、パソコン故障、データ流出等)についても、作成者は責任を負わないものといたします。特に、このソフトウェアは独自研究によるレジストリ編集を行っているため、その方法が完全ではなかったり、Windowsのバージョン・システム構成等の環境によって正常に動作しない可能性があります。場合によっては重大なトラブルを引き起こす可能性がありますので、そのようなリスクをご承知の上、ご利用ください。
なお、このソフトウェアを起動した時点で、免責事項を読んだかどうかにかかわらず、これらの免責事項に同意したものとみなします。
テンプレですが、どうぞご注意、ご理解くださいませ。

ライセンス

さて、このライブラリのライセンスをどうしようか考えましたが、SSIDProxyの開発に伴って作ったものということもあり、基本的にはSSIDProxyに準じ、それ以外に下記の条項を付け加えています。
  • このライブラリを改変してはならない。
  • 有償アプリケーションには使用してはならない。
  • 使用方法やバグに関するサポートをする責任を作者は負わない。
  • 完成したソフトウェアのどこか(ヘルプ、バージョン情報など)と、ReadMeなどのドキュメンテーションに私のライブラリを使用したことを明記すること。ただし、作者がこのライブラリを使用するときはその限りではない。
  • このライブラリを利用したアプリケーションをユーザーが配布するときに限って、作者に無断で再配布できるものとする。ただし、必要最小限のファイルに留めること。
今時クローズドソースも流行らないかもしれませんが、まあ、とりあえず現状はこのような形で。ニーズが出てきたら適宜ライセンスを変更してオープンソースにするかもしれません。

ダウンロード

SSIDProxyをダウンロードしてください。
SSIDProxy ver.1.1.1
そのうちの 
  • bin\ProxySwitcher.dll
  • bin\ja-JP\ProxySwitcher.resources.dll
の2つがProxySwitcherで必要なファイルです。プロジェクトからProxySwitcher.dllを参照をして使用してください。

0 件のコメント:

コメントを投稿