2025-04-27 07:49:33 -04:00

367 lines
11 KiB
Perl

# The documentation is at the __END__
package Win32::OLE::Variant;
require Win32::OLE; # Make sure the XS bootstrap has been called
use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK);
use Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
Variant
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_UI1
VT_ARRAY VT_BYREF
);
@EXPORT_OK = qw(CP_ACP CP_OEMCP);
# Automation data types.
sub VT_EMPTY {0;}
sub VT_NULL {1;}
sub VT_I2 {2;}
sub VT_I4 {3;}
sub VT_R4 {4;}
sub VT_R8 {5;}
sub VT_CY {6;}
sub VT_DATE {7;}
sub VT_BSTR {8;}
sub VT_DISPATCH {9;}
sub VT_ERROR {10;}
sub VT_BOOL {11;}
sub VT_VARIANT {12;}
sub VT_UNKNOWN {13;}
sub VT_UI1 {17;}
sub VT_ARRAY {0x2000;}
sub VT_BYREF {0x4000;}
# For backward compatibility
sub CP_ACP {0;} # ANSI codepage
sub CP_OEMCP {1;} # OEM codepage
use overload '""' => sub {$_[0]->As(VT_BSTR)},
'0+' => sub {$_[0]->As(VT_R8)},
fallback => 1;
sub Variant {
return Win32::OLE::Variant->new(@_);
}
1;
__END__
=head1 NAME
Win32::OLE::Variant - Create and modify OLE VARIANT variables
=head1 SYNOPSIS
use Win32::OLE::Variant;
my $var = Variant(VT_DATE, 'Jan 1,1970');
$OleObject->{value} = $var;
$OleObject->Method($var);
=head1 DESCRIPTION
The IDispatch interface used by the Perl OLE module uses a universal
argument type called VARIANT. This is basically an object containing
a data type and the actual data value. The data type is specified by
the VT_xxx constants.
=head2 Functions
=over 8
=item Variant(TYPE, DATA)
This is just a function alias of the C<Win32::OLE::Variant->new()>
method (see below). This function is exported by default.
=back
=head2 Methods
=over 8
=item new(TYPE, DATA)
This method returns a Win32::OLE::Variant object of the specified
TYPE that contains the given DATA. The Win32::OLE::Variant object
can be used to specify data types other than IV, NV or PV (which are
supported transparently). See L<Variants> below for details.
For VT_EMPTY and VT_NULL variants, the DATA argument may be omitted.
For all non-VT_ARRAY variants DATA specifies the initial value.
To create a SAFEARRAY variant, you have to specify the VT_ARRAY flag in
addition to the variant base type of the array elemnts. In this cases
DATA must be a list specifying the dimensions of the array. Each element
can be either an element count (indices 0 to count-1) or an array
reference pointing to the lower and upper array bounds of this dimension:
my $Array = Win32::OLE::Variant->new(VT_ARRAY|VT_R8, [1,2], 2);
This creates a 2-dimensional SAFEARRAY of doubles with 4 elements:
(1,0), (1,1), (2,0) and (2,1).
A special case is the the creation of one-dimensional VT_UI1 arrays with
a string DATA argument:
my $String = Variant(VT_ARRAY|VT_UI1, "String");
This creates a 6 element character array initialized to "String". For
backward compatibility VT_UI1 with a string initializer automatically
implies VT_ARRAY. The next line is equivalent to the previous example:
my $String = Variant(VT_UI1, "String");
If you really need a single character VT_UI1 variant, you have to create
it using a numeric intializer:
my $Char = Variant(VT_UI1, ord('A'));
=item As(TYPE)
C<As> converts the VARIANT to the new type before converting to a
Perl value. This take the current LCID setting into account. For
example a string might contain a ',' as the decimal point character.
Using C<$variant->As(VT_R8)> will correctly return the floating
point value.
The underlying variant object is NOT changed by this method.
=item ChangeType(TYPE)
This method changes the type of the contained VARIANT in place. It
returns the object itself, not the converted value.
=item Copy(DIM)
This method creates a copy of the object. If the original variant had
the VT_BYREF bit set then the new object will contain a copy of the
referenced data and not a reference to the same old data. The new
object will not have the VT_BYREF bit set.
my $Var = Variant(VT_I4|VT_ARRAY|VT_BYREF, [1,5], 3);
my $Copy = $Var->Copy;
The type of C<$Copy> is now VT_I4|VT_ARRAY and the value is a copy of
the other SAFEARRAY. Changes to elements of C<$Var> will not be reflected
in C<$Copy> and vice versa.
The C<Copy> method can also be used to extract a single element of a
VT_ARRAY | VT_VARIANT object. In this case the array indices must be
specified as arguments:
my $Int = $Var->Copy(1, 2);
C<$Int> is now a VT_I4 Variant object containing the value of element (1,2).
=item Dim()
Returns a list of array bounds for a VT_ARRAY variant. The list contains
an array reference for each dimension of the variant's SAFEARRAY. This
reference points to an array containing the lower and upper bounds for
this dimension. For example:
my @Dim = $Var->Dim;
Now C<@Dim> contains the following list: C<([1,5], [0,2])>.
=item Get(DIM)
For normal variants C<Get> returns the value of the variant, just like the
C<Value> method. For VT_ARRAY variants C<Get> retrieves the value of a single
array element. In this case C<DIM> must be a list of array indices. E.g.
my $Val = $Var->Get(2,0);
As a special case for one dimensional VT_UI1|VT_ARRAY variants the C<Get>
method without arguments returns the character array as a Perl string.
print $Var->Get, "\n";
=item LastError()
The use of the C<Win32::OLE::Variant->LastError()> method is deprecated.
Please use the C<Win32::OLE->LastError()> class method instead.
=item Put(DIM, VALUE)
The C<Put> method is used to assign a new value to a variant. The value will
be coerced into the current type of the variant. E.g.:
my $Var = Variant(VT_I4, 42);
$Var->Put(3.1415);
This changes the value of the variant to C<3> because the type is VT_I4.
For VT_ARRAY type variants the indices for each dimension of the contained
SAFEARRAY must be specified in front of the new value:
$Array->Put(1, 1, 2.7);
The are a few special cases for one-dimensional VT_UI1 arrays: The VALUE
can be specified as a string instead of a number. This will set the selected
character to the first character of the string or to '\0' if the string was
empty:
my $String = Variant(VT_UI1|VT_ARRAY, "ABCDE");
$String->Put(1, "123");
$String->Put(3, ord('Z'));
$String->Put(4, '');
This will set the value of C<$String> to C<"A1CZ\0">. If the index is omitted
then the string is copied to the value completely. The string is truncated
if it is longer than the size of the VT_UI1 array. The result will be padded
with '\0's if the string is shorter:
$String->Put("String");
Now C<$String> contains the value "Strin".
=item Type()
The C<Type> method returns the type of the contained VARIANT.
=item Unicode()
The C<Unicode> method returns a C<Unicode::String> object. This contains
the BSTR value of the variant in network byte order. If the variant is
not currently in VT_BSTR format then a VT_BSTR copy will be produced first.
=item Value()
The C<Value> method returns the value of the VARIANT as a Perl value. The
conversion is performed in the same manner as all return values of
Win32::OLE method calls are converted.
=back
=head2 Overloading
The Win32::OLE::Variant package has overloaded the conversion to
string and number formats. Therefore variant objects can be used in
arithmetic and string operations without applying the C<Value>
method first.
=head2 Class Variables
The Win32::OLE::Variant class used to have its own set of class variables
like C<$CP>, C<$LCID> and C<$Warn>. In version 0.1003 and later of the
Win32::OLE module these variables have been eleminated. Now the settings
of Win32::OLE are used by the Win32::OLE::Variant module too. Please read
the documentation of the C<Win32::OLE->Option> class method.
=head2 Constants
These constants are exported by default:
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_UI1
VT_ARRAY
VT_BYREF
=head2 Variants
A Variant is a data type that is used to pass data between OLE
connections.
The default behavior is to convert each perl scalar variable into
an OLE Variant according to the internal perl representation.
The following type correspondence holds:
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
Note that VT_BSTR is a wide character or Unicode string. This presents a
problem if you want to pass in binary data as a parameter as 0x00 is
inserted between all the bytes in your data. The C<Variant()> method
provides a solution to this. With Variants the script writer can specify
the OLE variant type that the parameter should be converted to. Currently
supported types are:
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
When VT_DATE and VT_CY objects are created, the input parameter is treated
as a Perl string type, which is then converted to VT_BSTR, and finally to
VT_DATE of VT_CY using the C<VariantChangeType()> OLE API function.
See L<Win32::OLE/EXAMPLES> for how these types can be used.
=head2 Variant arrays
A variant can not only contain a single value but also a multi-dimensional
array of values (called a SAFEARRAY). In this case the VT_ARRAY flag must
be added to the base variant type, e.g. C<VT_I4 | VT_ARRAY> for an array of
integers. The VT_EMPTY and VT_NULL types are invalid for SAFEARRAYs. It
is possible to create an array of variants: C<VT_VARIANT | VT_ARRAY>. In this
case each element of the array can have a different type (including VT_EMPTY
and VT_NULL). The elements of a VT_VARIANT SAFEARRAY cannot have either of the
VT_ARRAY or VT_BYREF flags set.
The lower and upper bounds for each dimension can be specified separately.
They do not have to have all the same lower bound (unlike Perl's arrays).
=head2 Variants by reference
Some OLE servers expect parameters passed by reference so that they
can be changed in the method call. This allows methods to easily
return multiple values. There is preliminary support for this in
the Win32::OLE::Variant module:
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";
After the C<GetSize> method call C<$x> and C<$y> will be set to
the respective sizes. They will still be variants. In the print
statement the overloading converts them to string representation
automatically.
VT_BYREF is now supported for all variant types (including SAFEARRAYs).
It can also be used to pass an OLE object by reference:
my $Results = $App->CreateResultsObject;
$Object->Method(Variant(VT_DISPATCH|VT_BYREF, $Results));
=head1 AUTHORS/COPYRIGHT
This module is part of the Win32::OLE distribution.
=cut