by Hippo2000(2001/2/20)
Jan Duboisさんにはメールで了解をいただきました。
内容等が間違っていたら修正します。ご連絡ください。
Win32::OLE::Variant - OLE バリアント変数の作成と変更
use Win32::OLE::Variant;
my $var = Variant(VT_DATE, 'Jan 1,1970');
$OleObject->{value} = $var;
$OleObject->Method($var);
Perl OLEモジュールによって使われるIDispatch インターフェースはバリアント(VARIANT)と呼ばれる汎用的な引数型を使います。これは基本的にデータ型と実際のデータ値をもったオブジェクトです。データ型はVT_xxx定数により指定されます。
use Win32::OLE::Variant qw(:DEFAULT nothing);
# ...
$object->{Property} = nothing;
これは以下のVisual Basic ステートメントと同じ効果を持ちます。
Set object.Property = Nothing
nothing() はデフォルトではエクスポートされません。
Win32::OLE::Variant->new()
メソッドの単なる別名関数です。(下記をご覧ください)この関数はデフォルトでエクスポートされます。VT_EMPTY と VT_NULL variantsについては、 DATA引数を省略することができます。すべてのVT_ARRAYではない variant については、DATAを初期値を指定します。
SAFEARRAY variantを作るためには、配列要素の基本型に加えてVT_ARRAYフラグを指定しなければなりません。この場合、DATAは配列を次元を指定するリストでなければなりません。各要素は要素数(0から指定数-1を示します)またはこの次元での上限下限を示す配列リファレンスのどちらかにすることができます:
my $Array = Win32::OLE::Variant->new(VT_ARRAY|VT_R8, [1,2], 2);
これはdoubleで4つの要素:((1,0), (1,1), (2,0) そして(2,1) をもった2次元のSAFEARRAYを作成します。
特別なケースは、文字列DATA引数をもった1次元のVT_UI1配列の作成です。
my $String = Variant(VT_ARRAY|VT_UI1, "String");
これは"String"で初期化された6つの文字配列を作成します。後方互換性のため、文字列初期値をもったVT_UI1は自動的にVT_ARRAYが暗黙のうちに設定されます。次の行は前の例と同じです:
my $String = Variant(VT_UI1, "String");
本当に1文字 VT_Ul1 バリアントが必要なのであれば、数値の初期値を使って作らなければなりません:
my $Char = Variant(VT_UI1, ord('A'));
As はVARIANT をPerlの値に変換される前に新しい型に変換します。これは現在のLCID設定も勘案します。例えばある文字列bんは小数点文字として,'が入っているかもしれません。$variant->As(VT_R8)を使うと浮動小数点値を返します。元になるバリアントは、このメソッドによって変更されません。
my $Var = Variant(VT_I4|VT_ARRAY|VT_BYREF, [1,5], 3);
my $Copy = $Var->Copy;
$Copyの型は今やVT_I4|VT_ARRAY であり、値は他のSAFEARRAYのコピーです。$Varの要素を変更しても$Copyには反映されませんし、その逆でも同じです。
CopyメソッドはVT_ARRAY | VT_VARIANT オブジェクトの1つの要素を取り出すために使うこともできます。この場合、配列のインデックスはリストDIMで指定されなければなりません:
my $Int = $Var->Copy(1, 2);
$Int は今や要素(1,2)の値をもった
VT_I4 バリアント・オブジェクトです。
use Win32::OLE::NLS qw(:LOCALE);
LOCALE_NOUSEROVERRIDEは、コントロール・パネル・アプリケーションを通して行われた変更をすべて無視しして、指定されたロケールのためのシステム・デフォルト通貨フォーマットを使うように指示します。
ハッシュ・リファレンスには以下のキーを入れることができます:
NumDigits 小数の桁数
LeadingZero 数値フィールドで前に0をつけるかどうか
Grouping 数字区切りの各グループの桁数
DecimalSep 小数点文字列
ThousandSep 桁区切り文字
NegativeOrder Win32::OLE::NLS/LOCALE_ICURRENCYを参照
PositiveOrder Win32::OLE::NLS/LOCALE_INEGCURRを参照
CurrencySymbol 通貨記号
例えば:
use Win32::OLE::Variant;
use Win32::OLE::NLS qw(:DEFAULT :LANG :SUBLANG :DATE :TIME);
my $lcidGerman = MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_NEUTRAL));
my $v = Variant(VT_CY, "-922337203685477.5808");
print $v->Currency({CurrencySymbol => "Tuits"}, $lcidGerman), "\n";
以下のようになります:
-922.337.203.685.477,58 Tuits
LOCALE_NOUSEROVERRIDE このロケールでのシステム・デフォルト日付書式を使う
DATE_SHORTDATE 短い日付書式を使う(デフォルト)
DATE_LONGDATE 長い日付書式を使う
DATE_YEARMONTH 年/月 書式を使う
DATE_USE_ALT_CALENDAR もしあれば代替 カレンダーを使う
DATE_LTRREADING 左から右 読込順レイアウト
DATE_RTLREADING 右から左 読込順レイアウト
Win32::OLE::NLSモジュールから定数を利用することができます:
use Win32::OLE::NLS qw(:LOCALE :DATE);
以下の要素を日付書式設定文字列を構成するために使うことができます。文字は正確に以下で示される通りに指定されなければなりません(例えば"dd"は"DD"ではありません)。書式コードの間のどこにでも空白を入れることができます。その他の、逐語的なテキストはシングル・クォートに含まれなければなりません:
d 日
dd 日。1桁であれば前に0がつく
ddd 曜日 : 3文字の省略名 (LOCALE_SABBREVDAYNAME)
dddd 曜日 : フルネーム (LOCALE_SDAYNAME)
M 月
MM 月。1桁であれば前に0がつく
MMM 月: 3文字の省略名 (LOCALE_SABBREVMONTHNAME)
MMMM 月: フルネーム (LOCALE_SMONTHNAME)
y 年 最後の2桁
yy 年 最後の二桁。10よりも小さければ前に0がつく。
yyyy 年 4桁により表される
gg 時代/年号 文字列
例えば:
my $v = Variant(VT_DATE, "April 1 99");
print $v->Date(DATE_LONGDATE), "\n";
print $v->Date("ddd',' MMM dd yy"), "\n";
は以下のように出力します:
Thursday, April 01, 1999
Thu, Apr 01 99
my @Dim = $Var->Dim;
すると @Dim
には以下のリストが入ります: ([1,5],
[0,2]).
my $Val = $Var->Get(2,0);
1次元のVT_UI1|VT_ARRAYバリアントの特別場合、引数のないGetメソッドはPerl文字列として文字配列を返します:
print $String->Get, "\n";
Win32::OLE::Variant->LastError()メソッドを使うことは非難されます。代わりにWin32::OLE->LastError()クラスメソッドを使ってください。use Win32::OLE::NLS qw(:LOCALE);
LOCALE_NOUSEROVERRIDE はメソッドにコントロール・パネル・アプリケーションを通してなされたかもしれない変更をすべて無視して、指定されたロケールのためのシステム・デフォルト数値書式を使うように指示します。
ハッシュ・リファレンスには以下のキーのものを入れることができます:
NumDigits 小数の桁数
LeadingZero 数値フィールドで前に0をつけるかどうか
Grouping 桁区切りの桁数
DecimalSep 小数点の文字列
ThousandSep 桁区切りの文字列
NegativeOrder Win32::OLE::NLS/LOCALE_INEGNUMBERを参照
例:
my $Var = Variant(VT_I4, 42);
$Var->Put(3.1415);
型がVT_I4なので、これはバリアントの値を3に変更します。
VT_ARRAY 型バリアントでは、SAFEARRAYに含まれている各次元のためのインデックスが当たらし値の前に指定されなければなりません:
$Array->Put(1, 1, 2.7);
一度のPut()メソッド呼出しを使ってSAFEARRAYの*各*要素に値を代入することも可能です:
$Array->Put([[1,2], [3,4]]);
この場合、Put()への引数は配列リファレンスで、Perlリストのリストの次元はSAFEARRAYの次元と厳密にあっていなければなりません。
1次元のVT_Ul1配列のためにはいくつか特別なケースがあります:VALUEは数値の代わりに文字列として指定することができます。これは選択された文字をその文字列の最初の文字に設定します。または文字列が空であれば'\0'にします:
my $String = Variant(VT_UI1|VT_ARRAY, "ABCDE");
$String->Put(1, "123");
$String->Put(3, ord('Z'));
$String->Put(4, '');
これは$Stringの値を"A1CZ\0"に設定します。もしインデックスが省略されると、文字列は完全に値へコピーされます。もしVT_Ul1配列の大きさよりも長ければ、その文字列は切り捨てられます。もし短ければ'\0'で埋められます。
$String->Put("String");
$Stringには値"Strin"が入ります。
PutはVariantオブジェクトそのものを返します。そのためPut呼出しをつなげておこなうことができます:
$Array->Put(0,0,$First_value)->Put(0,1,$Another_value);
LOCALE_NOUSEROVERRIDE このロケールでのシステム・デフォルト時刻書式
TIME_NOMINUTESORSECONDS 分または秒を使わない
TIME_NOSECONDS 秒を使わない
TIME_NOTIMEMARKER 時刻マーカーを使わない
TIME_FORCE24HOURFORMAT つねに24時間制の時刻フォーマットを使う
定数はWin32::OLE::NLSモジュールから利用することができます:
use Win32::OLE::NLS qw(:LOCALE :TIME);
以下の要素を日付書式設定文字列を構成するために使うことができます。文字は正確に以下で示される通りに指定されなければなりません(例えば"dd"は"DD"ではありません)。書式コードの間のどこにでも空白を入れることができます。その他の、逐語的なテキストはシングル・クォートに含まれなければなりません:
h 時; 12時間制
hh 時 1桁であれば前に0がつく;12時間制
H 時; 24時間制
HH 時 1桁であれば前に0がつく;24時間制
m 分
mm 分 1桁であれば前に0がつく
s 秒
ss 秒 1桁であれば前に0がつく
t A や Pのような1字時刻マーカー文字列
tt AMまたはPMのような複数文字時刻マーカー文字列
例えば:
my $v = Variant(VT_DATE, "April 1 99 2:23 pm");
print $v->Time, "\n";
print $v->Time(TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER), "\n";
print $v->Time("hh.mm.ss tt"), "\n";
これは以下のように出力します:
2:23:00 PM
14:23:00
02.23.00 PM
Win32::OLE::Variant パッケージは文字列と数値書式の変換がオーバーロードされています。このためVarinatオブジェクトはValueメソッドを先に適用することなしに、算術と文字列操作で使うことができます。
Win32::OLE::Variantクラスは独自のクラス変数の集合を$CP、$LCIDそして$Warnをもつようにしてきました。Win32::OLEモジュールのバージョン0.1003
以降では、これらの変数は削除されています。今ではWin32::OLEの設定が
Win32::OLE::Variant モジュールでも使われます。Win32::OLE->Option
クラス・メソッドのドキュメントをお読みください。
デフォルトで以下の定数がエクスポートされます:
VT_EMPTY
VT_NULL
VT_I2
VT_I4
VT_R4
VT_R8
VT_CY
VT_DATE
VT_BSTR
VT_DISPATCH
VT_ERROR
VT_BOOL
VT_VARIANT
VT_UNKNOWN
VT_DECIMAL
VT_UI1
VT_ARRAY
VT_BYREF
VT_DECIMAL は許可されるOLEオートメーション・データ型の公式リストにはありません。しかしMicrosoft ADOでさえ、レコードセット・リールドの値をVT_DECIMAL形式で返しているようです。
バリアント(Variant) はOLE接続の間でデータを渡すために使われるデータ型です。
デフォルトの動きは各Perlスカラ変数を内部のperl表現に合わせてOLEバリアントに変換します。以下の型対応が取られます:
C type Perl type OLE type
------ --------- --------
int IV VT_I4
double NV VT_R8
char * PV VT_BSTR
void * ref to AV VT_ARRAY
? undef VT_ERROR
? Win32::OLE object VT_DISPATCH
VT_BSTRが全角文字またはUnicode文字列であることに注意。これはパラメータとしてバイナリ・データを渡そうとすると、データのすべてのバイトの間に0x00が挿入されるという問題を起こします。Variant()メソッドはこれを解決する方法を提供します。Variantでスクリプトの作者は、そのパラメータが変換されるべきOLEバリアント型を指定することができます。現在は以下の型がサポートされています:
VT_UI1 unsigned char
VT_I2 signed int (2 bytes)
VT_I4 signed int (4 bytes)
VT_R4 float (4 bytes)
VT_R8 float (8 bytes)
VT_DATE OLE Date
VT_BSTR OLE String
VT_CY OLE Currency
VT_BOOL OLE Boolean
VT_DATEとVT_CYオブジェクトが作成されると、入力パラメータはPerl文字列型として扱われます。これはVT_BSTRに変換され、最後にVariantChangeType OLE API関数を使ってVT_CYまたはVT_DATEに変換されます。これらがどのように使うことができるかについては、 Win32::OLE/EXAMPLES をご覧ください。
バリアントは1つの値を持つだけでなく、値の多次元配列ももつ事ができます(SAFEARRAYと呼ばれます)。この場合、VT_ARRAYフラグが基本バリアント型に付与されなければなりません。例えばVT_I4|VT_ARRAYは整数の配列です。VT_EMPTYとVT_NULL型はSAFEARRAYには不適切です。バリアントの配列を作成することも可能です:VT_VARIANT | VT_ARRAY。この場合、配列の各要素を異なる型(VT_EMPTY、VT_NULLも含めて)にすることができます。VT_VARIANT SAFEARRAYの要素はVT_ARRAYまたはVT_BYREFのどちらのフラグも設定することはできません。
各次元の上限、下限は個別に指定することができます。(Perlの配列とは違って)すべてが同じ下限をもつ必要はありません。
いくつかのOLEサーバーは、メソッド呼出しの中で変更できるように、リファレンスによってパラメータが渡されることを期待します。これはメソッドに複数の値を戻すことを簡単にします。Win32::OLE::Variantモジュールでこれの予備的なサポートがされています:
my $x = Variant(VT_I4|VT_BYREF, 0);
my $y = Variant(VT_I4|VT_BYREF, 0);
$Corel->GetSize($x, $y);
print "Size is $x by $y\n";
GetSizeメソッド呼出しの後、$xと$yは対応する大きさに設定されます。これらはまだバリアントです。printステートメントでは、オーバーロードがそれらを自動的に文字列表現に変換します。
VT_BYREF は今やすべてのバリアント型でサポートされています(SAFEARRAYも含めて)。これはOLEオブジェクトをリファレンスで渡すためにも使われます:
my $Results = $App->CreateResultsObject;
$Object->Method(Variant(VT_DISPATCH|VT_BYREF, $Results));
このモジュールはWin32::OLEディストリビューションの一部です。
ご意見、ご質問はこちらの掲示板で受け付けています。
またメールは河馬屋(Nifty)にお願いします。