Reputation: 25117
package My::Win32::Console;
use warnings;
use strict;
use parent qw( Win32::Console );
sub new {
my($class, $param1, $param2) = @_;
my $self = {};
if (defined($param1)
and ($param1 == constant("STD_INPUT_HANDLE", 0)
or $param1 == constant("STD_OUTPUT_HANDLE", 0)
or $param1 == constant("STD_ERROR_HANDLE", 0)))
{
$self->{'handle'} = _GetStdHandle($param1);
# https://rt.cpan.org/Public/Bug/Display.html?id=33513#txn-577224:
$self->{'handle_is_std'} = 1;
}
else {
$param1 = constant("GENERIC_READ", 0) | constant("GENERIC_WRITE", 0) unless $param1;
$param2 = constant("FILE_SHARE_READ", 0) | constant("FILE_SHARE_WRITE", 0) unless $param2;
$self->{'handle'} = _CreateConsoleScreenBuffer($param1, $param2,
constant("CONSOLE_TEXTMODE_BUFFER", 0));
}
bless $self, $class;
return $self;
}
sub DESTROY {
my($self) = @_;
# https://rt.cpan.org/Public/Bug/Display.html?id=33513#txn-577224:
#_CloseHandle($self->{'handle'});
_CloseHandle($self->{'handle'}) unless $self->{'handle_is_std'};
}
1;
__END__
When I try to apply this patch https://rt.cpan.org/Public/Bug/Display.html?id=33513#txn-577224 with the help of this module I get this error message:
# Use of inherited AUTOLOAD for non-method My::Win32::Console::constant()
# is no longer allowed at C:/Strawberry/perl/site/lib/My/Win32/Console.pm line 10.
Is there a way to make this work?
Upvotes: 3
Views: 1632
Reputation: 385764
The problem is that you are calling a number of Win32::Console subs as if they were in My::Win32::Console.
Solution 1: Properly reference the subs.
constant
with Win32::Console::constant
._CreateConsoleScreenBuffer
with Win32::Console::_CreateConsoleScreenBuffer
._CloseHandle
with Win32::Console::_CloseHandle
.Solution 2: Import the needed subs.
Add the following:
BEGIN {
*My::Win32::Console::constant = \&Win32::Console::constant;
*My::Win32::Console::_CreateConsoleScreenBuffer = \&Win32::Console::_CreateConsoleScreenBuffer;
*My::Win32::Console::_CloseHandle = \&Win32::Console::_CloseHandle;
}
That said, I think inheritance is inappropriate here (and poorly done). Monkey-patching would be preferred.
package Win32::Console::PatchForRT33513;
use strict;
use warnings;
use Win32::Console qw( );
{
my $old_new = Win32::Console->can('new');
my $new_new = sub {
my ($class, $param1, $param2) = @_;
my $self = $old_new->(@_);
$self->{handle_is_std} = 1
if defined($param1)
&& ( $param1 == Win32::Console::constant("STD_INPUT_HANDLE", 0)
|| $param1 == Win32::Console::constant("STD_OUTPUT_HANDLE", 0)
|| $param1 == Win32::Console::constant("STD_ERROR_HANDLE", 0)
);
return $self;
};
no warnings qw( redefine );
*Win32::Console::new = $new_new;
}
{
my $old_DESTROY = Win32::Console->can('DESTROY');
my $new_DESTROY = sub {
my ($self) = @_;
Win32::Console::_CloseHandle($self->{handle}) if !$self->{handle_is_std};
};
no warnings qw( redefine );
*Win32::Console::DESTROY = $new_DESTROY;
}
1;
This way, modules that inherit from Win32::Console won't break, and you'll still be able to keep using
use Win32::Console qw( STD_OUTPUT_HANDLE );
my $c = Win32::Console->new(STD_OUTPUT_HANDLE);
as long as you do the following first:
use Win32::Console::PatchForRT33513;
Upvotes: 5
Reputation: 118605
I don't know if I can explain it any better than perldiag
(what you'd see if you use diagnostics
)
Use of inherited AUTOLOAD for non-method %s() is deprecated.
This will be fatal in Perl 5.28 (D deprecated) As an (ahem) accidental feature, "AUTOLOAD" subroutines are looked up as methods (using the @ISA hierarchy) even when the subroutines to be autoloaded were called as plain functions (e.g. "Foo::bar()"), not as methods (e.g. "Foo->bar()" or "$obj->bar()").
This bug will be rectified in future by using method lookup only for methods' "AUTOLOAD"s. However, there is a significant base of existing code that may be using the old behavior. So, as an interim step, Perl currently issues an optional warning when non-methods use inherited "AUTOLOAD"s.
The simple rule is: Inheritance will not work when autoloading non-methods. The simple fix for old code is: In any module that used to depend on inheriting "AUTOLOAD" for non-methods from a base class named "BaseClass", execute "*AUTOLOAD = \&BaseClass::AUTOLOAD" during startup.
In code that currently says "use AutoLoader; @ISA = qw(AutoLoader);" you should remove AutoLoader from @ISA and change "use AutoLoader;" to "use AutoLoader 'AUTOLOAD';".
This feature was deprecated in Perl 5.004, and will be fatal in Perl 5.28.
The quickest fix, if you are expecting to be able to use AUTOLOAD
in this class, is to say
*My::Win32::Console::AUTOLOAD = \&Win32::Console::AUTOLOAD
Upvotes: 3