Ruby Library Report 【第 4 回】 Win32Utils

著者: Daniel Berger, 訳・編: 立石 孝彰

原文: Ruby Library Report --- [No.4] Using Win32Utils

編者前書き

Win32Utils は、Windows における様々な機能を利用するためのライブラリを 集めたものです。Win32Utils を使うと、今までよりも多様な作業を、Windows 上で行えるようになることと思います。 そこで今回、著者である Daniel Berger 氏によって、この Win32Utils を 紹介して頂くことにしました。(著: 立石)

登録データ

Win32Utils の利用

はじめに

Win32Utils プロジェクトは、もともとクロスプラットフォームなクライアント・ サーバ・アプリケーションを作成することから始まったものです。 Windows サービスというものを覚えたての頃の話ですが、Windows 版の Ruby に は、悲しいほどにわずかなライブラリしかないことを実感しました。

そこで、Windows 上でのライブラリとして、Perl と Python にどのようなものが あるのかを調査し、Windows API の勉強をしながら、それらを移植することにしま した。 RubyForge に、Win32Utils プロジェクトを設け、Park Heesob と Shashank Date の二人を開発者として迎えました。そして、彼らとともに、Ruby の Windows 用の ライブラリを Perl や Python のものと並ぶようにするための作業に取り掛かりま した。

今のところ、Win32Utils には、12 個を超えるパッケージがあります。それらは、 ネイティブなMutex、セマフォ、イベント (イベントログとサービス・イン フォメーション)、プロセス情報、ユーザ・グループ管理、ネイティブ・ファイル、クリップ ボード、パイプ、タスク・スケジューラー、ショートカット、SAPI に対する インターフェイスを提供します。今回は、この中のいくつかを見ていくことにします。

ライブラリレポート

WIN32-CLIPBOARD

このパッケージは、Windows において Ruby からクリップボードを利用するための インターフェイスを提供します。このインターフェイスを用いて、クリップボードの データに対して、以下のように、取得・追加・消去が出来ます。

 require "win32/clipboard"
 include Win32

 # クリップボードのデータの取得
 puts "Data on clipboard was: " + Clipboard.data

 # クリップボードにデータを追加
 Clipboard.data = "test"

 # クリップボードのデータを再び取得
 puts "Data on clipboard is now: " + Clipboard.data

 # クリップボードのデータを消去
 Clipboard.empty

ここで、現在のリリースでは、例えば、画像をコピー・ペーストするなどの、テキス ト以外のフォーマットをサポートしていません。しかし、将来的に、この機能は追加 するつもりです。

WIN32-ETC

このパッケージを用いることによって、ローカルシステム、または、リモートシステム におけるユーザとグループに関する情報を取得することができます。 また、Admin モジュールを用いることによって、ユーザとグループの管理も可能です。

win32-etc が提供する API は、標準添付の 'etc' パッケージに基づいて設計されて います。標準の etc パッケージは、Unix システムにおいて利用されるものですが、 win32-etc の API は、標準の etc パッケージとほとんど同等のものです。

 require "win32/etc"
 include Win32

 # リモートシステム上のユーザ情報の表示
 Etc.passwd('\\some_machine'){ |pwstruct|
   p pwstruct
 }

 # ローカルシステム上のグループ情報の表示
 Etc.group{ |gstruct|
   p gstruct
 }

win32-etc と、標準の etc パッケージには、2つの違いがあります。まず第一に、リ モートシステムから情報を得るために、Etc モジュールにおけるほとんどのメソッドの 引数に、ホストを与えることができます。 次に、Etc.passwd と Etc.group が生成する Struct オブジェクトのメンバは、標 準の etc パッケージのものと似てはいますが異なります。

さて、ユーザやグループを追加したり、一般的な管理を行うためには、Admin モジュール を利用します。

 require "win32/etc"
 include Win32

 # ユーザの追加
 Etc::Admin.add_user(
   :user_name   => "some_user",
   :password    => "abc123def",
   :home_dir    => "C:\\foo_user",
   :description => "random text",
   :host	        => "\\some_machine",
   :flags       => Etc::Admin::ACCOUNTDISABLE
 )

 # グループの追加
 Etc::Admin.add_group(
   :group_name  => "foo",
   :description => "Test Group",
   :local?      => true,
   :users       => %w/matz guido larry/
 )

Admin モジュールを使うことによって、パスワードの設定はもちろん、既存のユーザや グループの設定や削除などを行うことができます。

WIN32-FILE

このパッケージは、Ruby の File クラスに対して、Win32 特有のメソッドを追加し、 また、いくつかのメソッドを取り替えます。 Win32 システムにおけるファイルの特徴には、それらがプロパティを持つというもの です。 エクスプローラー・ウィンドウを使うのであれば、ファイルの上で右クリックをして、 「プロパティ」を選択してください。そうすれば、そのファイルについて、より詳細 なプロパティを見ることができます。 win32-file パッケージを使うことによって、このようなプロパティの取得や設定 を行うことができます。

 require "win32/file"
 # 'foo.txt' のプロパティ
 my_file = "C:\\Temp\\foo.txt"
 File.compressed?(my_file) 	# true or false
 File.read_only?(my_file)	         # true or false

 # プロパティの設定
 File.open(my_file,"w+"){ |fh|
   fh.compressed = true
   fh.read_only = true
 }

さらに、ファイルに関して、セキュリティ情報の閲覧と設定を行うことができます。*1 セキュリティ情報を表しているキーと値の組のハッシュを取得するためには、 File.get_permissions を使います。しかし、値は整数値であるため、それらの値 を File.securities を用いて可読な表現に変換する必要があります。*2

 require "win32/file"

 # 'foo.txt'の現在のセキュリティ情報の取得
 File.get_permissions("C:\\Temp\\foo.txt").each{ |acct,perms|
   puts "Account: #{acct}:"
   puts File.securities(perms).inspect()
 }

また、File.set_permissions を用いて、パーミッションを設定することも可能です。

win32-file パッケージのその他の特徴として、ファイルの暗号化・複合化、Native IO に対する read と write のためのメソッドがあり、そしてまた、多くの属性に関するメソッドを持ちます。

最後に、いくつかの中心となる File メソッドは win32-file において再定義されています。 なぜなら、それらは Win32 システムのために実装されたものではないか、あるいは、うまく 動かなかったためです。原稿執筆時点において、File.blockdev?, File.chardev?, File.size がそのようなメソッドです。*3

WIN32-SOUND

このパッケージは、wav ファイルやシステムサウンドなどのサウンドを Win32 システム上 で再生させることができます。

 require "win32/sound"
 include Win32

 # wav ファイルの再生
 Sound.play("foo.wav")

 # システムサウンドの再生
 Sound.play("SystemAsterisk",Sound::ALIAS)

また、ビープ音を鳴らすことや、システム上のサウンドデバイスの情報を取得すること、 または、再生中のサウンドの音量をチェックすることや、停止することもできます。

WIN32-SHORTCUT

このパッケージを用いると、Win32 システム上において、ショートカットの作成と設定を 行うこができます。ショートカットは、ファイルやプログラムへのリンク(.lnkファイル) です。典型的に、左下に小さな矢印のあるアイコンとして、デスクトップ上やエクスプロー ラ上に表示されています。*4

 require "win32/shortcut"
 include Win32

 s = Shortcut.new('c:\test.lnk')
 s.description = "test link"
 s.path = 'c:\winnt\notepad.exe'
 s.show_cmd = Shortcut::SHOWNORMAL
 s.working_directory = "C:\\"
 s.save

上記の例では、"notepad.exe" への "test.lnk" というショートカットを 'C:\' ディレ クトリ中に作成しました。そして、"test link" という description を付けました。*5 Shortcut#working_directory は、実行可能ファイルが実行されるときのディレクトリ を表すもので、この例では 'C:\' です。 Shortcut#show_cmd は、GUI アプリケーションが、どのように実行開始されるのかを示 すもので、SHOWNORMAL, SHOWMINIMIZED, SHOWMAXIMIZED を与えることができます。 また、アイコンの関連付け、引数の指定、ホットキーの割り当てなどの情報を取得・設定 することができます。

WIN32-TASKSCHEDULER

このパッケージは、ローカルシステム、あるいは、リモートシステムにおいて、スケ ジュールされたタスクを管理・作成することができます。 スケジュールされたタスクは、Unix における 'cron' と似たもので、指定された 間隔や日時にプログラムを実行することができます。

 require "win32/taskscheduler"
 include Win32

 t = TaskScheduler.new

 # 既存のすべてのタスクを列挙
 t.enum.each{ |task|
   puts "Task name: #{task}"
 }

ここで、TaskScheduler オブジェクトの生成によって、実際に、システム上に新しい タスクが作成されているわけではありません。TaskScheduler プログラムと連携する ためのオブジェクトを生成しているに過ぎません。 新しいタスクを作成する場合、タスクの項目と、そのトリガーを追加し、それをセーブ する必要があります。

 trigger = {
   "start_month"  => 4,
   "start_day"    => 11,
   "start_hour"   => 7,
   "start_minute"	 => 14,
   "trigger_type"	 => TaskScheduler::DAILY,
   "type"         => { "days_interval" => 2 }
 }

トリガーは、ハッシュを用いて記述します。*6 上記のトリガーを用いると、(今年の)4月11日の7:14amにタスクが開始し、毎日一度、 タスクが実行されます。用意したトリガーを用いて、新しいタスクの項目を、以下の通 りに作成できます。

 t.new_work_item("foo",trigger)
 t.application_name = "ruby foo.exe"
 t.save

このサンプルでは、実際にタスクスケジューラ中に項目を作成しています。*7 そして、この項目をセーブするのはもちろん、実際に実行すべきプログラムを指定しな ければなりません。TaskScheduler#save が呼ばれるまで、タスクの項目は生成され ません。ここでのサンプルは、便宜的に、以下のように簡単に記述できます。

 t = TaskScheduler.new("foo",trigger)
 t.save

新しい項目を作成する以外にも、既存の項目の編集・削除、プライオリティの設定、 最も最近の実行時間のようなタスクに関する情報の取得、実行中のタスクの停止を行 うことができます。 また、一つの項目に対して、複数のトリガーを追加することもできます。

その他のライブラリについて

その他に、次のパッケージがあります。

  • Windows サービスの設定を行う win32-service
  • イベントログの read/write を行う win32-eventlog
  • ネイティブなパイプの実装である win32-pipe
  • プロセス間通信に関する win32-ipc, win32-event, win32-semaphore, win32-mutex のパッケージ群
  • Win32版のforkの実装を含んだプロセス処理のための win32-process
  • ネイティブな mmap の実装である win32-mmap
  • ディレクトリやファイルの変更を監視する win32-changenotify
  • MS Sound API へのインターフェイスを提供する win32-sapi
  • Win32システム上で動作する popen3 の実装である win32-open3

これ以外にも、実験的なものとして、ネイティブスレッドを利用するための win32-thread を、Windows の fiber API*8 を用いて開発中です。

まとめ

本稿の目的は、これまでに Win32 システムに対する Ruby のライブラリをご存知 でない方に、そのような有用なライブラリが利用できることを紹介することです。 そして、これらのライブラリによって、Win32 システム上の実開発において、Ruby が使えるようになることを期待します。

著者について

Daniel Berger は、1996 年からプログラマとして働き、2000 年から Ruby を使い 始めました。現在、クライアント・サーバ・アプリケーションの作成からレポート生成、 さらには、思いつく限りの用途に、Ruby を使っています。 また、Pragmatic Programmers の好意により、Pragmatic Bookshelf から 発売が予定されている "Programming Ruby on Win32" の著者です。

*1 NTFS ファイルシステムを利用している場合のみ可能です。

*2 将来的に、単純に配列を返すように変更する予定です。

*3 元の File.size は、ファイルサイズが 2GB 未満であればうまく動作します。

*4 ショートカットは、シンボリックリンクとは異なることに注意してください。

*5 ショートカット上で、右クリックをして「プロパティ」を選択することで詳細を見ることができます。

*6 有効なキーについては、docs を参考にしてください。また、"type" に対する値はハッシュであることに注意してください。

*7 もし目で確認したければ、「スタート」→「コントロールパネル (Windows XP の場合はクラシック表示)」→「タスク」を選択してください。

*8 fiber とは、スレッドのようなもので、Win32 API の CreateFiber() によって生成できます。