NAME

Win32::CLR - Use .NET Framework facilities in Perl

SYNOPSIS

use Win32::CLR;
use utf8;

# binmode STDOUT, ":encoding(Shift_JIS)"; # japanese character set

# creating instance
my $dt1 = Win32::CLR->create_instance("System.DateTime", 2007, 8, 9, 10, 11, 12);

# getting property
print $dt1->get_property("Year"), "\n"; # 2007

# calling method
my $dt2 = $dt1->call_method("AddYears", 3);
print $dt2->get_property("Year"), "\n"; # 2010

my $asm = "System.Windows.Forms, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089";

# loading assembly by name
Win32::CLR->load($asm);

# after loading assembly, System.Windows.Forms.* classes can be used
Win32::CLR->call_method(
    "System.Windows.Forms.MessageBox", # type
    "Show",    # method
    "Message", # parameter
    "Title"    # parameter
);

# creating generic instance
my $generic = "System.Collections.Generic.Dictionary<System.String, System.Int32>";
my $dict = Win32::CLR->create_instance($generic);
$dict->set_property("Item", "ABC", 4321); # dict["ABC"] = 4321;
print $dict->get_property("Item", "ABC"), "\n"; # 4321

DESCRIPTION

Win32::CLR provides utility methods to using Microsoft .NET Framework, also known as Common Language Runtime. It is available for creating object, calling method, accessing field or property, converting perl subroutine to delegate, loading assembly.

CLASS METHODS

Win32::CLR->create_instance("TYPE", @PARAMS)

Creates .NET Framework object of TYPE. The constructor that matches @PARAMS is used.

my $dt = Win32::CLR->create_instance(
    "System.DateTime",
    2007, 8, 9, 10, 11, 12
);
Win32::CLR->call_method("TYPE", "NAME", @PARAMS)

Calls the static method declared in TYPE. @PARAMS must be primitive value or Win32::CLR instance. If @PARAMS contain array reference, it is converted to System.Array.

# in .net
# static void MyType::Foo(String^ param);

# in perl
Win32::CLR->call_method("MyType", "Foo", "foo");

# static void MyType::Foo2(String^ param1, Int32 param2);
Win32::CLR->call_method("MyType", "Foo2", "foo", 4321);

# static void MyType::Foo3(array<Object^>^ params);
Win32::CLR->call_method("MyType", "Foo3", ["foo", "bar", ...]);
Win32::CLR->get_field("TYPE", "NAME", [$INDEX])

Returns the static field declared in TYPE. If field has index, optional parameter $INDEX can be used.

# in .net
# field = MyType::Foo;

Win32::CLR->get_field("MyType", "Foo");

# MyType::Foo[0]
Win32::CLR->get_field("MyType", "Foo", 0);
Win32::CLR->set_field("TYPE", "NAME", [$INDEX, ] $PARAM)

Sets $PARAM in the static field declared in TYPE. $PARAM must be primitive value or Win32::CLR instance. If field has index, optional parameter $INDEX can be used.

Win32::CLR->get_property("TYPE", "NAME", [$INDEX])

Same as get_field, returns the static property declared in TYPE. Optionally, $INDEX can be used.

# in .net
# dict["ABC"]
$dict->get_property("Item", "ABC");
Win32::CLR->set_property("TYPE", "NAME", [$INDEX, ] $PARAM)

Same as set_field, sets $PARAM in the static property declared in TYPE. Optionally, $INDEX can be used.

# in .net
# dict["ABC"] = 4321;
$dict->set_property("Item", "ABC", 4321);
Win32::CLR->get_value("TYPE", "NAME", [$INDEX])

If property exists in TYPE, calls get_property, or otherwise calls get_field.

Win32::CLR->set_value("TYPE", "NAME", [$INDEX, ] $PARAM)

Same as get_value, sets $PARAM in static property or field.

Win32::CLR->add_event("TYPE", "NAME", $DELEG)

Sets event handler in the static event declared in TYPE. $DELEG must be System.Delegate or subroutine reference.

my $deleg = Win32::CLR->create_delegate(
    "System.EventHandler",
    sub {print "do something"},
);
$button->add_event("Click", $deleg);
$button->remove_event("Click", $deleg);

# directly, but addition only!
$button->add_event("Click", sub {print "do something"});
Win32::CLR->remove_event("TYPE", "NAME", $DELEG)

Removes event handler $DELEG from TYPE. $DELEG must be System.Delegate.

Win32::CLR->create_delegate("TYPE", $CODE)

Creates System.Delegate from perl subroutine. $CODE can contain "sub_name" or \&sub_ref. TYPE is delegate type (ex. System.EventHandler).

my $deleg = Win32::CLR->create_delegate(
    "System.EventHandler",
    sub {
        my ($obj, $event_args) = @_;
        # do something ...
    }
);
Win32::CLR->create_array("TYPE", @PARAMS)

Creates TYPE of System.Array. @PARAMS is setted.

my $array = Win32::CLR->create_array("System.String", "A", "B", "C");
$array->call_method("GetValue", 0); # A
$array->call_method("GetValue", 1); # B
$array->call_method("GetValue", 2); # C
Win32::CLR->create_enum("TYPE", "VALUE1, VALUE2, ...")

Creates System.Enum value. TYPE is enum type, VALUES contain list of named constants delimited by commas.

my $binding_flags = Win32::CLR->create_enum(
    "System.Reflection.BindingFlags",
    "InvokeMethod, NonPublic"
);
Win32::CLR->load("NAME")

Loads assembly by AssemblyQualifiedName. If assembly loaded once, it comes to be able to use the type in assembly. Loaded assembly is cached in memory, so reloading assembly is not required. NAME must be long form of the assembly name. It returns loaded System.Reflection.Assembly object.

my $name =
    "System.Windows.Forms, Version=2.0.0.0,
    Culture=neutral, PublicKeyToken=b77a5c561934e089";
# $asm can be ignored
my $asm = Win32::CLR->load($name);
my $button = Win32::CLR->create_instance("System.Windows.Forms.Button");
Win32::CLR->load_from("PATH")

Loads assembly from file. PATH is path to assembly file. It returns loaded System.Reflection.Assembly object.

Win32::CLR->has_member("TYPE", "NAME", [$MEMBER_TYPE])

Checks TYPE has member NAME. $MEMBER_TYPE is System.Reflection.MemberTypes constants delimited by commas. Default is Method, Field, Property, Event.

if ( Win32::CLR->has_member("System.String", "Length", "Field, Property") ) {
    print "System.String has Length\n";
}

INSTANCE METHODS

Win32::CLR instance has similar methods to class methods.

$obj->call_method("NAME", @PARAMS)
$obj->get_field("NAME", [$INDEX])
$obj->set_field("NAME", [$INDEX, ] $PARAM)
$obj->get_property("NAME", [$INDEX])
$obj->set_property("NAME", [$INDEX, ] $PARAM)
$obj->get_value("NAME", [$INDEX])
$obj->set_value("NAME", [$INDEX, ] $PARAM)
$obj->add_event("NAME", $DELEG)
$obj->remove_event("NAME", $DELEG)
$obj->has_member("NAME", [$MEMBER_TYPE])
$obj->get_addr()

Returns object address. Can be used for Inside-out class.

$obj->derived_from("TYPE")

Like UNIVERSAL::isa, returns $obj is derived from TYPE.

$obj->to_string()

Converts $obj to perl primitive string.

CREATING GENERIC INSTANCE

If you want to create generic instance, use optional parameter type enclosed by "<>".

my $name = "System.Collections.Generic.Dictionary<System.String, System.Int32>";
my $dict = Win32::CLR->create_instance($name);

Also System.Type.GetType form can be used.

my $name = "System.Collections.Generic.Dictionary`2[System.String, System.Int32]";
my $dict = Win32::CLR->create_instance($name);

GENERIC TYPE EXAMPLE

"Generic< Generic<Type1, Type2>, Type3 >"   # recursive
"Generic< Generic`2[Type1, Type2], Type3 >" # mixing

my $type = <<"TYPE"; # assembly qualified form
System.Collections.Generic.Dictionary<
    [
        System.String, mscorlib, Version=2.0.0.0,
        Culture=neutral, PublicKeyToken=b77a5c561934e089
    ],
    System.Int32
>, mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
TYPE

# creating generic delegate
my $deleg = Win32::CLR->create_delegate(
    "System.Action<System.String>",
    sub { print $_[0] }
);

CALLING GENERIC METHOD

Like creating generic type, generic method can be used.

$obj->call_method("method<System.String>", @params);

TYPE CONVERSION

Win32::CLR automatically converts primitive value between .net and perl.

.net -> perl
    Boolean                      -> perl bool
    SByte, Int16, Int32, Int64   -> perl int
    Byte, UInt16, UInt32, UInt64 -> perl unsigned int
    Single, Double               -> perl double
    Char, String, Decimal        -> perl string(utf8 flag on)
    null(nullptr)                -> perl undef
    other                        -> perl Win32::CLR instance

perl -> .net
    Win32::CLR instance -> Object
    perl int            -> Int32  -> cast target
    perl unsigned int   -> UInt32 -> cast target
    perl string         -> Char, String, Decimal
    perl double         -> Double -> cast target
    perl undef          -> null(nullptr)

OVERLOAD

Following operators are overloaded.

"" bool == != + - * / % > >= < <= ++ --

my $dt1 = Win32::CLR->create_instance("System.DateTime", 2007, 8, 9, 10, 11, 12);
my $dt2 = Win32::CLR->create_instance("System.DateTime", 2008, 8, 9, 10, 11, 12);
print "$dt1";
$dt1 == $dt1;
$dt1 != $dt2;
$dt > $dt2;
$dt < $dt2;

If you want compare instance equality, use get_addr method.

$dt->get_addr() == $dt->get_addr()

AUTOLOAD

When calling method named /^(get|set)_\w+/, it is converted to get_value or set_value. If not /^(get|set)_/, converted to call_method. Underscore is ignored and name is ignorecase.

$obj->get_year()    -> $obj->get_value("Year")
$obj->get_y_e_Ar()  -> $obj->get_value("Year")
$obj->set_year(1)   -> $obj->set_value("Year", 1)
$obj->add_years(2)  -> $obj->call_method("AddYears", 2)
$obj->AddYears(2)   -> $obj->call_method("AddYears", 2)
$obj->aDd__yEaRs(2) -> $obj->call_method("AddYears", 2)

BUGS AND WARNINGS

More tests and documents are required.

COPYRIGHT & LICENSE

Copyright 2007 Toshiyuki Yamato, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.