| Win32 FAQ |
perlwin32faq8 - 一般的なプログラミング
General programming questions about Perl for Win32に関する一般的なプログラミングの質問
Perl for Win32には、Win32レジストリ関数が用意されています。 Perl for Win32に付属している win32modドキュメントをチェックして ください。
レジストリの機能がよくわからない場合、レジストリのキーというのはディレクトリのようなもので、値というのはファイルのようなものであると覚えておけばよいでしょう。トップレベルキーというのがいくつかありますが、これは一種のドライブのようなものです。
なお、レジストリについてよく理解していない内は、あまりレジストリをいじり回さない方がよいでしょう。
名前つきパイプはプロセス間通信を行うための機構で、主に (Win32プラットフォームのような)Microsoftのオペレーティングシステム で用いられます。名前つきパイプはファイルと同じように扱うことが できます。
名前つきパイプの名前はUNC(Universal Naming Convention)名で、
\\servername\pipe\pipenameのように表します。
servernameは接続しようとしているサーバーの名前で、
これが.の場合にはカレントコンピューターを意味します。
pipeは決まり文句です。pipenameはMicrosoft SQL Server用のsqlのようなパイプ名です。
ファイルと同じように、名前つきパイプに対してopen()、close()、read()、print() といった関数を使うことができます。しかし、名前つきパイプは実際にはファイルではないため、
sysread()やsyswrite()は使用できません。
CPANのアーカイブには、名前付きパイプを生成するのに用いられるWin32Pipeというプログラムがあります。
ゼロからスタートで、TCP/IPのインフラが整っている場合は、IPC機構には名前つきパイプではなくソケットを使うことを検討してください。
Perl for Win32に同梱されているスクリプトサンプルにソケットを使ったものがあります。 サンプルはperlをインストールしたディレクトリの下のegというサブディレクトリにあります。
ソケットサーバに関しては、Perl for Win32でソケットサーバを書くにはどうすればよいのでしょうか? を参照してください。
初期のバージョンのPerl for Win32では、ファイルハンドルと同じようにソケットを読み書きすることはできませんでした。しかし、現在のバージョンではフルサポートされているので、あまり心配する必要はありません。 使っているバージョンでうまく動かない場合は、ActiveStateから最新版を入手してください。(Perl for Win32インタプリタはどこで入手できますか?参照)
Perl for Win32をビルドする際、ソケットをファイルハンドルのように動作させるUSE_SOCKETS_AS_FILEHANDLESをセットする必要はありません。
セットしても害は生じませんが、必須ではありません。
perlをインストールしたディレクトリの下のegというディレクトリに、TCP-SERVERというソケットサーバーのサンプルがあります。 一般的にいって、UNIXでのソケットプログラミング情報はPerl for Win32でも有効です。 詳しくは perlipcというドキュメントを参照してください。
一時に複数のクライアントにサービスできるサーバを開発する必要がある場合は、IO::Selectモジュールに目を通してください。 このモジュールを使うと、複数のクライアントからのopenコネクションを管理できるようになります。 コネクションの個々のリクエストはキューに入れられるので、サーバのレスポンスがよくなければなりませんが、このアプローチでうまくいくはずです。 以下のサンプルは、Erik OlsonのPerlモジュールを使ったプログラミング(O'Reilly社のWin32 Perl Resource Kitの一分冊)を改作したものです。:
use IO::Socket;
use IO::Select;
# listenするソケットを生成
#
my $listener =
IO::Socket::INET->new( LocalPort => 8008, Listen => 5, Reuse => 1 );
die "Can't create socket for listening: $!" unless $listener;
print "Listening for connections on port 8008\n";
my $readable = IO::Select->new; # 新しいIO::Selectオブジェクトを生成
$readable->add($listener); # それにlistenerを追加
while(1) {
# 会話の準備ができたソケットのリストを入手する
#
my ($ready) = IO::Select->select($readable, undef, undef, undef);
foreach my $s (@$ready) {
# Is it a new connection?
#
if($s == $listener) {
# コネクションをacceptし、読み取り可能リストに追加する
#
my $new_sock = $listener->accept;
$readable->add($new_sock) if $new_sock;
print $new_sock "Welcome!\r\n";
} else { # 確立済みのコネクションだった
my $buf = <$s>; # 1行分読み取ってみる
# 他方に誰かいたか?
#
if( defined $buf ) {
# 相手がgoodbyeと言ったらソケットを閉じる。
# そうでなければ、相手が言ったことをエコーする。
#
if ($buf =~ /goodbye/i) {
print $s "See you later!\n";
$readable->remove($s);
$s->close;
} else {
print $s "You said: $buf\n";
}
} else { # クライアントが切断した
$readable->remove($s);
$s->close;
print STDERR "Client Connection closed\n";
}
}
}
}
詳しくは、IO::SocketとIO::Selectのドキュメントを参照してください。 使用するPerlがスレッドが有効になっているバージョンであれば、Perl for Win32でもマルチスレッドサーバを書くことができます。しかし、Perl 5.005ではスレッドはまだ実験段階なので、その機能を使うには注意が必要です。
Net::FTPを参照してください。Net::FTPはlibnetバンドルの一部で、CPANで入手できます。 また、Perl Package Manager(PPM)を使ったインストールも可能です。
Aldo CalpiniがWININETライブラリを使ってFTP及びHTTPを行うPerl for Win32エクステンションを開発しました。 これはアルファテスト中ですが、彼のWebページ http://www.divinf.it/dada/perl/から入手できます
libwww-perlバンドル(LWP)は、PerlのWWWアクセス用モジュールのコレクションです。 LWPはCPANからソース形式で入手することができます。 また、Perl Package Manager(PPM)を使ってインストールすることもできます。 将来は、LWPもPerlのバイナリリリースに含まれるようになるかもしれません。
Aldo CalpiniがWININETライブラリを使ってFTP及びHTTPを行うPerl for Win32エクステンションを開発しました。 これはアルファテスト中ですが、彼のWebページ http://www.divinf.it/dada/perl/から入手できます
Perl for Win32に同梱されているWin32::NetAdminというエクステンションがあります。これは非常に低レベルなインターフェースですが、このモジュールを 使うとユーザーやグループの管理をすることが可能になります。
Perl for Win32ではシリアルポートはファイルと同じようにオープンでき ます。COM1をオープンするには以下のようにします。:
open( PORT, "+>COM1" ) or die "Can't open COM1: $!";
標準入出力関数(read()やprint())を使うとファイルハンドルを読み書きすることができます。しかし、システム関数(sysread()やsyswrite())を使用してはなりません。
(テストはしていませんが、)ヘイズのコマンドセットを使っているモデムは、コマンドの終端にキャリッジリターン(\n)ではなくランフィード(\r)を要求するので要注意といわれています。
本当は正しく動いています。 正しくない使い方をしているので、間違った結果になっているのです。 以下に示すコードを試してみてください。これは、あるディレクトリの下の全サブディレクトリをチェックするものです。:
$path = shift;
$path = "." unless $path;
opendir( DIR, $path )
or die "Can't open $path: $!";
while ( $entry = readdir( DIR ) ) {
$type = ( -d "$path\\$entry" ) ? "dir" : "file"; # $pathが大事!
print "$type\t$entry\n";
}
closedir( DIR );
ありがちな間違いは、-dの引数に$pathを付け忘れるというものです。
その場合、perlはカレントディレクトリのファイルを対象にしているのだと考えます。
対象としたいディレクトリがカレントディレクトリにはない場合は、-eは偽となりますし、当然-dも偽となります。
ただし、すべてのディレクトリに必ず存在する.と..は例外です。
Win32プラットフォームでは、テキストファイルとバイナリファイルの間には大きな 違いがあります。テキストファイルでは、"\r\n" というキャラクタはディスクから読み出されたときに"\n"に変換されますし、^Zというキャラクタはファイルの終端(end-of-file)を示す目印として読み込まれます。 バイナリファイルではこのような変換は行われません。
これはテキストファイルではうまくいきますが、バイナリファイルを読み書きしようとすると厄介なことになります。 ファイルに^Zがあると読み書きが異常終了してしまうし、^Zがない場合でも、\nから\r\nへの変換のためにファイルのバイト数が変わってしまうのはほぼ確実です。
この問題は、Perl for Win32及び使用しているCのランタイムライブラリが、デフォルトではテキストモードでファイルをオープンすることにあります。 Perlでバイナリ用に使用するファイルハンドルに対しては、そのファイルハンドルがバイナリモードであることを明示する必要があります。 幸運にも、それを行うbinmodeという関数があります。 詳しくは perlfuncというドキュメントを参照してください。
次のスクリプトは、バイナリファイルをコピーするものです。 binmodeを使ってファイルハンドルのモードを設定している点に注意してください。
open( INFILE, "<$infile" );
open( OUTFILE, ">$outfile" );
binmode( INFILE ); binmode( OUTFILE ); # バイナリファイルには必須!
while ( read( INFILE, $buffer, 1024 ) ) {
print OUTFILE $buffer;
}
close( INFILE );
close( OUTFILE );
Win32プラットフォームでは、'\'というキャラクタを(C:\like\thisのように)ファイル名の中のパスの区切り文字として使っています。 しかし、perlではラインフィードキャラクタ("\n")やタブキャラクタ("\t")のような特殊なキャラクタを表わすために、エスケープコードとして'\'を使っています。
そのため、以下のようにしてファイルをオープンしようとするとエラーとなります。
open( MYFILE, "C:\temp\newfile.txt" );
解決方法の一つはそれぞれの'\'を'\\'に置き換えて、本当はエスケープではなく文字として使用するつもりであることを示すことです。
open( MYFILE, "C:\\temp\\newfile.txt" );
別の解決策は、文字列展開しないシングルクォートを使うことです。これで、特殊キャラクタは使わないということがPerlに伝わります。:
open( MYFILE, 'C:\temp\newfile.txt' );
最後に、パス中のディレクトリ部を区切るのに / キャラクタを使うこともできます。 /をディレクトリ区切り文字ではなく、オプションの前置詞として取り扱うプログラムもいくつかあるので、外部プログラムをコールする際は / を使わないようにしなければなりません。 しかし、Perl for Win32(及び実際には全Win32API)は、/がディレクトリ区切り文字であることを認識しているので、/を使うとUNIXとWin32の間のスクリプトのポートはずっと楽になります。:
open( MYFILE, '/temp/newfile.txt' );
シングルクォート(') とダブルクォート(")の違いについては、詳しくはperlopドキュメントを参照してください。
これは終端文字列がスクリプトの最後の行にがある時に発生する不思議なエラーです。以下のようなスクリプトでは、:
print <<"END";
The snake is old, and his skin is cold.
END
perlは、ENDという単語とその後にラインフィードキャラクタ(\n)だけがある行を 探します。 ENDがスクリプトの最後の行にある場合、 ENDの後でリターンキーを叩くことを忘れてはなりません。そうすれば、それが終端文字列であることをperlが認識するようになります。
ほとんどのUNIXのテキストエディターは自動的にこれを行います。しかし、ほとんどのWindowsのテキストエディターはこれを行いません。 それで、問題となるのです
Perlのformatでも同じ問題が起こりうることに注意してください。 formatは、.だけの行を終端として扱います。 しかし、これはごく稀なことです。というのは、プログラマは、ファイルの最後ではなく先頭で出力用のフォーマットを指定することが多いからです。
この FAQ は、元々Evangelo Prodromou evangelo@endcontsw.comが作成し、保守していたものです。 現在、この文書は、O'Reilly社のBrian Jepson及びActiveState社のDavid GroveとDavid Dmytryshynが改訂・更新しています。
このFAQはパブリックドメインですが、使用する場合はオリジナルの作者について明示してください。
| Win32 FAQ |