Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Conditional use of Win32::TieRegistry

by hilitai (Monk)
on Nov 13, 2017 at 18:44 UTC ( #1203276=perlquestion: print w/replies, xml ) Need Help??

hilitai has asked for the wisdom of the Perl Monks concerning the following question:

I have a script that is used on Windows and Linux machines. Now, I need to have the script make a registry change on windows. Using Win32::TieRegistry seems reasonable, however I can't figure out a way to have this module work on Windows, and at the same time not get @INC errors on Linux.

My problem, I think, is that Win32::TieRegistry module appears to create a globally-scoped Registry object when the interpreter hits the 'use ...' statement. This object is used in all further interaction with the registry. If I try to put the 'use Win32::TieRegistry' into an 'eval {}', as I do when trying to load modules that may not exist, I get "Global symbol $Registry requires explicit package name..." errors.

Below is a simple script that encapsulates my problem. Two lines are commented out; if either one is uncommented, the script will work on either Windows *or* Linux; but if both are either left alone or uncommented, it fails on both platforms:

#!/usr/bin/perl use strict; my $usemod = 0; eval { require Win32::TieRegistry; }; if ($@) { warn "No module\n"; } else { $usemod = 1; } if ($usemod) { # my ($Registry, $IEKey); # If I expose this line, Windo +ws FAILS ($IEKey remains null); comment out, Windows WORKS # use Win32::TieRegistry(Delimiter=>"/"); # If I expose this line, L +inux FAILS (@INC compile error); comment out, Linux WORKS my $IEKey = $Registry->{'HKEY_CURRENT_USER/Software/Microsoft/Inter +net Explorer/Main/'}; print $IEKey, "\n"; } else { print "None of that stuff here\n"; }

Enlightenment sought, thanks in advance.

Replies are listed 'Best First'.
Re: Conditional use of Win32::TieRegistry
by pryrt (Monsignor) on Nov 13, 2017 at 19:57 UTC

    hilitai, with the ideas generated by the other Monks, I was able to come up with this, which worked for me on Win7 strawberry 5.24.1 and linux perl 5.8.5.

    #!/usr/bin/perl use strict; use warnings; my $usemod; # if you initialize `my $usemod = 0;`, then the BEGIN +block's assignment to $usemod is overridden, which you don't want our $Registry; # this will be overridden by Win32::TieRegistry's expo +rt of $Registry if in Windows, but BEGIN { local $\ = "\n"; if( $^O eq 'MSWin32' ) { eval { require Win32::TieRegistry; Win32::TieRegistry->import( Delimiter => '/' ); $usemod = 1; } } } if ($usemod) { my $IEKey = $Registry->{'HKEY_CURRENT_USER/Software/Microsoft/Inte +rnet Explorer/Main/'}; print "IEKey = '$IEKey'\n"; } else { print "None of that stuff here\n"; }
    • my 5.8.5 linux perl didn't like the use if ... (edit: or, at least, the way I tried... with some debug, it may have eventually worked), so I went with Discipulus's BEGIN block idea to make that run first

    • removing the = 0 on my $usemod; allowed the $usemod variable to update in the BEGIN block
    • used Perlbotics' suggestion of ->import(), though I included your Delimiter => '/' argument to the import
    • made $Registry a package variable using our, which then allowed the Win32::TieRegistry->import() to clobber it with the defined version from the module, while still allowing linux perl to compile the script

    edit#2: added use warnings; per best practices

    edit#3: added "perl" to "linux perl 5.8.5", so it wasn't implying that was the version of linux, but rather the version of perl

      Yes! Thank you all very much (and especially pryrt and haukex, who taught me something new today).

Re: Conditional use of Win32::TieRegistry
by Discipulus (Abbot) on Nov 13, 2017 at 19:01 UTC
    Hello hilitai

    you can check $^O to see if you are running on windows: see perlvar then require the module and eventully import, if the module uses Exporter's import.

    if ($^O eq 'MSWin32'){ require Win32::TieRegistry; Win32::TieRegistry -> import if Win32::TieRegistry -> can ("import" +); }

    See also use module if condition is met for suggestion about if module.

    PS this kind of things are worth to reside into a BEGIN block.


    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Conditional use of Win32::TieRegistry
by 1nickt (Abbot) on Nov 13, 2017 at 18:58 UTC

    Hi, see if:

    use if $^O =~ 'MSWin32', 'Win32::TieRegistry';
    (not sure about the regex, not a Windows user).

    Hope this helps!

    Update: added quoting to module name, see below

    The way forward always starts with a minimal test.

      Works for Windows, fails on Linux:

      Too few arguments to `use if' (some code returning an empty list in list context?) at /usr/lib/perl5/5.10.0/ line 7.

        Sorry, missed quoting the module (necessary if no args provided, like use if CONDITION, MODULE => ARGUMENTS;)

        Should be:

        use if $^O =~ 'MSWin32', 'Win32::TieRegistry';
        ... but I'm sure you saw that in the doc I linked to, right?

        The way forward always starts with a minimal test.
Re: Conditional use of Win32::TieRegistry
by haukex (Bishop) on Nov 13, 2017 at 19:54 UTC
    use warnings; use strict; my $have_tie_registry = defined eval q{ use Win32::TieRegistry Delimiter=>"/"; 1 }; if ($have_tie_registry) { print "Have module\n"; our $Registry; my $IEKey = $Registry->{'HKEY_CURRENT_USER/Software/' .'Microsoft/Internet Explorer/Main/'}; print "<$_>\n" for keys %$IEKey; } else { chomp( my $err = $@//'unknown' ); die $err if $^O eq 'MSWin32'; print "On $^O, don't have module (reason: '$err')\n"; } print "Continuing program...\n"; __END__ #### Linux: On linux, don't have module (reason: 'Can't locate Win32/TieRegistry.p +m in @INC (you may need to install the Win32::TieRegistry module) (@I +NC contains: ...) at (eval 1) line 1. BEGIN failed--compilation aborted at (eval 1) line 1.') Continuing program... ### Windows: Have module <...> <...> ... Continuing program...

    (Update: Note that as opposed to several of the other solutions here, this uses slightly different logic: if Win32::TieRegistry is available, it is used no matter which OS this is being run on; otherwise, if it's not available, that's only a fatal error if this is being run on Windows. Of course that logic can be changed, my point was mostly to show the my $have_module = eval q{ use Module; 1 }; technique.)

    See also:

Re: Conditional use of Win32::TieRegistry
by Perlbotics (Bishop) on Nov 13, 2017 at 18:56 UTC

    Uncomment this line:

    my ($Registry, $IEKey);
    and it will work. $Registry was not defined while using strictures.

    Output (linux):

    No module None of that stuff here


    Not tested on Windows, though (not available here). If that still fails, you have another problem. Perhaps, you need to call the import() class method:

    eval { require Win32::TieRegistry; Win32::TieRegistry->import(); };

    Update2: My try on a cleanup, after getting hands on a Windows system:

    use strict; use warnings; our $Registry; BEGIN { $Win32::TieRegistry::__LOADED = eval { require Win32::TieRegistry; Win32::TieRegistry->import( Delimiter => '/' ); 1; }; } sub use_mod { $Win32::TieRegistry::__LOADED; } print "On $^O\t-> "; if ( use_mod ) { my $IEKey = $Registry->{'HKEY_CURRENT_USER/Software/Microsoft/Inter +net Explorer/Main/'}; print 'Show status bar: ', $IEKey->{'/Show_StatusBar'}, "\n"; } else { print "None of that stuff here.\n"; } __DATA__ On MSWin32 -> Show status bar: yes On linux -> None of that stuff here.

      Yes, it works on Linux. But now it fails on Windows (the $IEKey variable should contain a value like Win32::TieRegistry=HASH(0x1dd000), but it is null).

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1203276]
Approved by Perlbotics
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (7)
As of 2021-04-16 21:30 GMT
Find Nodes?
    Voting Booth?

    No recent polls found