I'm trying to get the installation location of a program without checking a series of hard-coded paths, hoping to get it from the path stored in the Windows registry, but I get empty return values or error messages when I try to read the required key values.
I've read about Parsing windows registry using Perl, and I think I've incorporated all of the answers in my script, but I always get an empty result when I try reading a registry value, even when running from an elevated command-prompt to make sure the script has admin rights.
I first tried using Win32::TieRegistry, and as mentioned the returned value is empty, so then I tried just shelling out and using reg query
, but that gives an error about the key not being found. Running the same reg query
command outside of Perl successfully reads the key. What am I doing wrong?
Update: The root cause (pointed out in the couple answers I received) was trying to access a 64-bit registry view from a 32-bit Perl; by default, any 32-bit application in Windows is redirected to HKLM\Software\WOW6432Node
when trying to access HKLM\Software
keys, so I needed to find a way to avoid that since my key of interest does not exist in that location.
Perl script:
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
use Win32::TieRegistry (Delimiter => '/');
my $mykey = $Registry->{'HKEY_LOCAL_MACHINE/Software/ikv++ technologies ag/medini unite (x64)'};
my $mykeyval = $mykey->{'/Path'};
print " value=$mykeyval\n";
print Dumper $mykey;
my $sysCmd =`reg query "HKLM\\Software\\ikv++ technologies ag\\medini unite (x64)" /v Path`;
print " sysCmd=$sysCmd\n";
Output:
C:\Users\username\AppData\Local\Temp>perl test_reg_read.pl
Use of uninitialized value in concatenation (.) or string at test_reg_read.pl line 9.
value=
$VAR1 = {};
ERROR: The system was unable to find the specified registry key or value.
sysCmd=
Manual reg query
command outside of Perl:
C:\Users\username\AppData\Local\Temp>reg query "HKLM\Software\ikv++ technologies ag\medini unite (x64)" /v Path
HKEY_LOCAL_MACHINE\Software\ikv++ technologies ag\medini unite (x64)
Path REG_SZ C:\Program Files\ikv++ technologies ag\mediniUnite
Note, all this is running from an elevated command prompt for now; once it works there I was going to experiment with whether it is necessary.
As mentioned in Srgrn's answer, the problem stems from my Perl being 32-bit, running on a 64-bit system. Windows automatically redirects 32-bit processes to the Wow6432Node registry node when accessing HKLM\Software
unless specifically told to use 64-bit or 32-bit registry views with an access mode flag.
I could specify access with the old Win32API::Registry, but instead I chose to specify the access mode with TieRegistry's object functions:
#!/usr/bin/perl -w
use strict;
use Win32::TieRegistry (Delimiter => '/');
print "explicitly access 64-bit location:\n";
my $mykey = new Win32::TieRegistry
'HKEY_LOCAL_MACHINE/Software/ikv++ technologies ag/medini unite (x64)',
{ Access=>Win32::TieRegistry::KEY_READ()|0x0100, Delimiter=>'/' };
my $mykeyval = $mykey->GetValue('Path');
print " value=$mykeyval\n";
print " Values are: ";
print join(', ', $mykey->ValueNames);
print "\n";
print "explicitly access 32-bit location:\n";
$mykey = new Win32::TieRegistry
'HKEY_LOCAL_MACHINE/Software/ikv++ technologies ag/medini unite',
{ Access=>Win32::TieRegistry::KEY_READ()|0x0200, Delimiter=>'/' };
$mykeyval = $mykey->GetValue('Path');
print " value=$mykeyval\n";
print " Values are: ";
print join(', ', $mykey->ValueNames);
print "\n";
This gives results as expected for both the 32-bit and 64-bit keys, and additionally should work the same way in both 32-bit and 64-bit Perl (in theory anyway).
Note: I needed to specify the full namespace for the KEY_READ() function in my version of Perl to prevent compile errors, and I'm not certain whether there are named values for the 0x0100 and 0x0200 constants, so this may be rougher than needed on some systems, but it seems to work great for me!
Note: this also allows you to read the right version of a key with the same name in either 32-bit and 64-bit, so this answer is duplicated there.