miau's blog?

PerlScript

サクラエディタのマクロ掲示板にこんなのありまして。

[140] PerlScriptマクロを使うためのメモをジャンク置き場に

PerlScript って何?
と調べてみると、どうも VBScript や JavaScript と似たような感じで Perl が使えるらしい。
(よく見ると ActivePerl のマニュアルにも書いてあった)

で、早速使ってみたんですが・・・色々あったので、まず結論から。

・PerlScript で日本語を使う場合は、ファイル全体の文字数>スクリプト部分のバイト数 となるように調整する。

・PerlScript には MsgBox() なんて隠し関数がある模様。
(WScript.Shell の Popup() よりは楽?)

・ScriptControl を使えば VBScript 等も呼び出し可能。

・同一プロセスから Tk モジュールを複数回使用しようとすると、エラーとなる。
(別プロセスで実行することで回避可能)

・ファイルパスを利用した変数($0)、関数(require())、モジュール(IPC::Open2)は使えない。
 ただし、open() や Cwd は問題なく使える模様。

そんな感じで、以下詳細(長いので注意)。




■前提

 りーやさんによる「サクラエディタでPerlScriptマクロを使うためのメモ」(sakura-editor ブリーフケース内の PerlMacro.txt)を読んでるものとして話を進めてしまいます。


■日本語の使用

 スクリプトに日本語を使うと動作がおかしくなることはりーやさんが書いている通り。
 とはいえ、コメントには日本語使いたいし、文字列として日本語を出力する場合は必須なわけで。
 往生際悪く日本語を使い続けていると、なんとなく問題が見えてきた感じ。
 
 どうも、日本語を使った文字数ぶん、スクリプトの最後が削られてる様子。
 文字数とバイト数のカウントがごっちゃになっている部分があるっぽい。
 例えば、print "あいう"; ってのは 15 byte で 12 文字だけど、PerlScript はこういう場合、最初の 12 byte だけをスクリプトとして認識しているみたい。
(正確には 12 byte + '\0' の領域を確保するので、13 byte まで読み込まれてるんだけど。
 これは OllyDbg でちまちま処理追っている最中に確認できました)
 
 んー・・・だったら。
 例えば UTF-16 みたいに固定文字長の文字コード使えば問題ないんじゃない?
 
 ということで、試しに use encoding 'UTF-16' とかで書いてみたけど・・・こんなエラーが。
Can't locate object method "cat_decode" via package "Encode::Unicode"

 なにこれ?ということで、調べてみると・・・
 
 Encoding.pm - devdaily.com
 (ソース表示しないと Pod 部分がちゃんと見れないので注意)
 
 ということで、encoding プラグマで使う場合はそういう関数が必要、とのこと。
 まぁ、よくよく考えると UTF-16 って全部 2 byte なんだから、却って問題がひどくなる気がする。
 
 とりあえず、この問題の回避方法は、スクリプトの末尾に余計な文字列を付加すること。
 __END__ の後に書くなり、コメント山ほど書くなり。
 ファイル全体の文字数 > スクリプト部分のバイト数 になっていれば問題なく実行できるはず。
 
 ちなみにこの現象は一応報告しておきました。
 ActiveState Bug Database - Bug 40776 - 2-byte character problem with PerlScript
 英作文とか苦手なので、かなり胡散臭い英語になっていると思います。
 詳しい方ツッコミお願いします。
 
 ちなみに投稿後に同じ趣旨の投稿があるのに気づいた。
 ActiveState Bug Database - Bug 18521 - Can't use Japanese Kanji in script.
 4 年近く放っておかれてるんで、あまり対応する気ないのかも。


■WSF の使用(挫折)

 上のドキュメントに書いている通り、入力が必要な場面では DoMacro の InputBox() を使っていました。
 でもこの関数、キャンセルボタン押下時にデフォルト値を返すみたいで・・・ちょっと使い勝手が悪いです。
 ポータビリティが低下するのも問題ですし・・・ということで代替手段を考えてみた。
 
 IE 上では、VBScript と JScript の相互呼び出しが可能なわけで。
 それと同じようなことができないかなー、と。
 
 調べてみると、WSF ファイルというのがあるらしい。
 Windows スクリプト ファイル (.wsf) を使用する
 cscript ではうまく動作するようなので、試しにマクロで使ってみたけど・・・動作しない。
 
 ソースを眺めてみると、どうもサクラエディタは拡張子を元にレジストリを検索→エンジンの取得をしてるらしい。
 本当はどう扱うべきなんだろう?ということで、調べてみると・・・
 
 beruponの日記 - SakuraEditorでWSH
 
 なるほど。cscript.exe の中で XML の解析〜実行までやってるのではないか、と。
 サクラエディタ側でも実装できないかなー?
 XML の解析くらいならなんとかなりそうだけど、複数のエンジンを動作させるのって面倒そうな気がする。
 
 で、結局挫折したんだけど、一応このへん(Active Scriptiong 周り)ちょっと調べてみたので、メモ。
 
 Windows Script
 公式。
 
 Active Scripting FAQ
 定番らしい。
 
 Скрипт-технологии: JavaScript, VBScript, WSH
 状態遷移図とかあってわかりやすかった。
 
 
 cscript.exe とサクラエディタの動作も比較してみたので、ついでにメモ。
 
 ComTrace - blunck.info
 COM の呼び出しをトレースするソフト。
 Active Scriptiong 周りの呼び出しをトレースするには、ComTrace/IDL に
 Microsoft Visual Studio/VC98/Include/ACTIVSCP.IDL を放り込んでおく必要あり。
 
 サクラエディタのほうは問題なく取得できたけど、cscript.exe で WSF ファイルを実行した場合の処理は、なぜかうまく取得できないっぽい。
 普通のスクリプトを実行した場合はトレースできたし、サクラエディタと呼び出し順が違う部分も見受けられたけど、↑の状態遷移図を見る限り、特に問題なさげ。


■ScriptControl

 色々調べてると、ScriptControl オブジェクトで外部スクリプトの呼び出しが可能らしい。
 
 Script Control - Microsoft Scripting Technologies
 
 ということで、お手製 InputBox 関数。

sub InputBox
{
my @args = @_;
@args = map { encode('cp932', $_) } @args;
while (@args < 3) {
push @args, '';
}

my $sc = Win32::OLE->CreateObject("ScriptControl");
$sc->{Language} = "VBScript";
$sc->AddCode(<<EOC);
Function Main(prompt, title, default)
Main = InputBox(prompt, title, default)
End Function
EOC
my $ret = $sc->Run("Main", @args);
$ret = decode('cp932', $ret);

return $ret;
}

 UTF8 でスクリプト書いている(または use encoding してる)& use Encode していているものとして書いてます。
 ShiftJIS で動かしてる場合は encode と decode の行を削れば普通に動くと思います。
 キャンセル時は undef が返ってくれます。
 
 ちなみに AddCode で日本語渡そうとすると、確実に文字化けします。
 ShiftJIS で渡しても UTF8 で渡しても同じように化けるところをみると、どこかで変なエンコーディング処理が入ってるんだろうけど。
 
 エラー処理とかよくわからなかったので入れてないけど、まぁ基本的にエラー起きないはずなので、気にしない。


■InputBox() 周りでその他調べたこと

 別の方法として、WSC ファイルというのを使えば VBScript との相互呼び出しが可能らしい。
 
 WSH技術情報 - Windows Scripting Host Laboratory
 
 でもこれなら、DoMacro 使うのと同じだし、あまり意味ないか。
 
 
 その他の方法が好みであれば、こちらが参考になるかも。
 
 Windows Scripting Host 16 Input

■Tk モジュールの使用

 Perl で GUI を実装する方法として、Tk モジュールというのがあるわけですが。
 これも PerlScript で使ってみました。

use Tk;
my $mw = MainWindow->new();
MainLoop();

 なんか普通にうまくいった・・・と思いきや、同じプロセスから2回以上実行すると、妙なエラーが発生するみたいです。
 (cscript だと普通に動くので最初はサクラエディタの不具合かと思ったけど、EmEditor でも同じ現象でした)
 試しに、
system 'perl -e "use Tk; my $mw = MainWindow->new(); MainLoop();"'

 とやってみると、何度でも動作させられました。
 (ちなみに threads 使って別スレッドにするだけではダメでした)
 
 もうちょっと現象追ってみるつもりですが、Tk 側に問題ある気がする。
 他のモジュールは問題なく使えてるわけだし。
 
 ということで、標準出力経由で入力値受け取るような感じにすれば一応 Tk も使えました。
 IPC::Open2 でスクリプト渡して標準出力を受け取る形にしたかったんですが、IPC::Open2 は変なエラーを吐いてしまうので、結局外部スクリプトとして切り出すのが妥当かも。
 外部ファイル使うなら、普通に GUI のクライアント作ってもいいじゃん、という気もしますが・・・たぶんいずれバグもなくなって、Tk が普通に使える日が来るでしょうし。
 
 Tk は UTF8 のままで日本語使えるのも魅力。


■MsgBox()

OllyDbg で処理を追っていると、PerlSE.dll にこんな文字列があるのを見つけました。
usage: MsgBox($Message [, $Buttons [, $Title]]);

え。なにそれ。そんな関数実装されてるの?
ということで、試しに呼び出してみると・・・普通に使えました。

でもマニュアルにも書いてないし・・・普通気づかないのでは・・・。
ちょっとググってみると、変数やら関数やらの一覧がありました。

Dump PerlScript's Variables

他にめぼしい関数とかはないみたい。残念。

ということで、メッセージダイアログ出すだけなら、Win32::OLE とか使わなくてもいいみたい。
まぁ、マニュアルに書いてない関数なので、いきなり消えたりする可能性もありますけど。

あ、perl からも呼び出されるんなら Win32::OLE 使ったほうがいいかも。


■その他情報

 全然関係ない情報も混じってますけど。

 @IT:運用 Windows管理者のためのWindows Script Host入門 第1回 WSHの内部構造 1.Windows管理にWSHを活用しよう
 WSH の概要

 Axsh.exe demonstrates how to implement an active scripting host
 Scripting Host の実装例

 JavaScript の文字コード処理に関する覚書 by kanegon
 JavaScript や VBScript で文字コード周りで問題があったとき参考にするといいかも。

 趣味のJavaScriptなページ
 「JavaScript 重箱の隅」とか面白い。
posted at 21:14:41 on 2005-09-13 by miau - Category: TextEditor No Trackbacks - Permalink

TrackBack

このエントリにトラックバックはありません
現在トラックバックは受け付けていません。

Comments

りーや wrote:

拝見しました。すばらしいです

日本語がコメントで使えないのに対しては、今は require で逃げてました。
require や eval で実行前のコンパイルを回避させると、Perl と同じようにくらいは PerlScript でも日本語が使えるようです。

__END__ 以下に意味のないものを埋めるくらいならば、1; だけの一行で置き換えて取り込まれる側のスクリプトにするとスッキリはするかもしれません。どの道、逃げ道なので、現象報告までしていただいたのはすばらしいと思います。
2005-09-14 00:59:34

miau wrote:

コメントありがとうございました。おかげさまで「require() はできない」なんていう誤認識を改めることができました。

FILEさんの変更により、心置きなく require() できるようになったので、日本語問題の対応として、
・__END__ 以下にパディング
・外部スクリプトに切り出し
どちらの方法で行くか迷っているところです・・・。

また何かあったらマクロ掲示板とかに書かせていただきますね。
2005-09-19 21:00:48

No Name wrote:

実は、ぼくもPerlScriptで日本語使おうと
して同じ問題に直面しました。
いろいろ調べてみると日本語を使うと起こる
問題であることは分かったのですが、日本語を
使うと読み込むスクリプトのバイト数が少な
くなるというのは気がつきませんでした。
これって問題ですよね。
早く修正されることを期待します。
なお、printなどの文字列定数内に\x82\xa0
のようにしても同様の問題が発生します。
2005-12-07 15:46:47

miau wrote:

現象確認してから〜、と思ってたらレス遅くなってしまいました。すいません。

PerlScript って情報少ないから色々調べるの大変ですよね。普通の Perl のことを PerlScript と書いてる人もいたりしますし。

>なお、printなどの文字列定数内に\x82\xa0
>のようにしても同様の問題が発生します。

この現象、私の環境(ActivePerl 5.8.7.815)では確認できませんでした・・・。
2005-12-14 09:02:08

Add Comments

現在コメントは受け付けていません。
お手数ですが、 こちら のコメント欄にでも記載していただければと思います。