如何使继承的AUTOLOAD用于非方法工作?

时间:2018-08-18 06:38:58

标签: windows perl console

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__

当我尝试在此模块的帮助下应用此补丁https://rt.cpan.org/Public/Bug/Display.html?id=33513#txn-577224时,出现以下错误消息:

# 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.

有没有办法使这项工作成功?

2 个答案:

答案 0 :(得分:3)

问题是您正在调用许多Win32 :: Console子程序,就像它们在My :: Win32 :: Console中一样。


解决方案1:正确引用潜艇。

  • constant的五个实例替换为Win32::Console::constant
  • _CreateConsoleScreenBuffer的单个实例替换为Win32::Console::_CreateConsoleScreenBuffer
  • _CloseHandle的单个实例替换为Win32::Console::_CloseHandle

解决方案2:导入所需的订阅。

添加以下内容:

BEGIN {
   *My::Win32::Console::constant                   = \&Win32::Console::constant;
   *My::Win32::Console::_CreateConsoleScreenBuffer = \&Win32::Console::_CreateConsoleScreenBuffer;
   *My::Win32::Console::_CloseHandle               = \&Win32::Console::_CloseHandle;
}

也就是说,我认为继承在这里不合适(而且做得不好)。最好用猴子打补丁。

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;

这样,从Win32 :: Console继承的模块不会中断,您仍然可以继续使用

use Win32::Console qw( STD_OUTPUT_HANDLE );
my $c = Win32::Console->new(STD_OUTPUT_HANDLE);

只要您先执行以下操作:

use Win32::Console::PatchForRT33513;

答案 1 :(得分:3)

我不知道我能比perldiag更好地解释它(如果您use diagnostics会看到什么)

  

不赞成将继承的AUTOLOAD用于非方法%s()。

     

这将是       在Perl 5.28中致命           (已弃用D)作为(偶然)意外功能,“ AUTOLOAD”子例程           被视为方法(使用@ISA层次结构),即使           要自动加载的子例程称为普通函数(例如           

:“ Foo :: bar()”),而不是方法(例如“ Foo-> bar()”或“ $ obj-> bar()”)。

     

此错误将在以后仅通过使用方法查找来纠正           方法的“ AUTOLOAD”。但是,现有的基础很大           可能使用旧行为的代码。因此,作为过渡步骤,Perl           当前在非方法使用继承时发出可选警告           “ AUTOLOAD”。

     

简单的规则是:自动加载时继承不起作用           非方法。修改旧代码的简单方法是:在使用过的任何模块中           依赖于继承基类的非方法的“ AUTOLOAD”           名为“ BaseClass”,在执行期间执行“ * AUTOLOAD = \&BaseClass :: AUTOLOAD”           启动。

     

在当前显示“使用AutoLoader; @ISA = qw(AutoLoader);”的代码中           您应该从@ISA中删除AutoLoader并更改为“ use AutoLoader”;至           “使用AutoLoader'AUTOLOAD';”。

     

此功能在Perl 5.004中已弃用,在Perl中将是致命的           5.28。

最快的解决方法是,如果您希望能够在此类中使用AUTOLOAD,请说

*My::Win32::Console::AUTOLOAD = \&Win32::Console::AUTOLOAD