How do I make the 32-bit Perl read the 64-bit Windows registry?
I have a 32-bit perl installer. Using this I need to be able to install and uninstall both 32- and 64-bit applications.
Installing 32- and 64-bit is fine. Uninstalling 32-bit is also ok.
However, I have a problem while uninstalling 64-bit applications.
The application just knows the name of the application as seen in Add Remove programs in control panel. For instance it could be "Winzip 14.0" which is the display name for Winzip.
I use the following approach for uninstallation : I traverse to HKLM/Software/Microsoft/Windows/CurrentVersion/Uninstall
and parse the keys present there to see if Winzip is matching. If so i get the uninstall string from there.
my $register = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
$HKEY_LOCAL_MACHINE->Open($register,$hKey)||开发者_如何转开发 die $!;
#Then parse all the nodes and fetch the uninstall string
If the application is a 64-bit installation, then the uninstallation information will reside in HKLM/Software/Microsoft/Windows/CurrentVersion/Uninstall
.
However the above given perl installer code is trying to read from
HKLM/Software/WOW6432Node/Microsoft/Windows/CurrentVersion/Uninstall
So how do I make the Perl code running in a 32_bit process to read the registry value found in 64-bit hive? I am aware of the RegOpenKey()
API that takes KEY_WOW64_64KEY
parameter. But since it is a Windows API, I dont know if that will help. Even then, is there any other alternative?
Yes, you have to use KEY_WOW64_64KEY, there is no other workaround for a 32-bit process. Calling the Win32 API directly from Perl appears possible, judging from this web page.
You could also call the reg tool directly, instead of the batch file:
$WINDIR/system32/reg.exe
This is the default location for reg.exe when included with operating system.
$WINDIR/sysnative/reg.exe
This is the virtual location of the native 64-bit reg.exe when executed from a 32-bit process.
As you note in your question, it is possible to specify a 64-bit or 32-bit registry views with the KEY_WOW64_64KEY flag.
The old Win32API::Registry can specify the 64-bit registry with KEY_WOW64_64KEY, but these days it is better to use TieRegistry's object functions, which wraps the functionality to make it easier to work with the registry:
#!/usr/bin/perl -w
use strict;
use Win32::TieRegistry (Delimiter => '/');
print "registry 64-bit:\n";
my $mykey = new Win32::TieRegistry
'HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Uninstall',
{ Access=>Win32::TieRegistry::KEY_READ()|0x0100, Delimiter=>'/' };
print "\tValues are:\n";
print join("\n\t\t", $mykey->ValueNames);
print "\n";
#Getting a specific value's value
#$mykeyval = $mykey->GetValue('Path');
print "\tFiltered subkeys are:\n\t\t";
print join("\n\t\t", grep(!/\{[-A-Fa-f0-9]+\}/, $mykey->SubKeyNames));
print "\n";
print "registry 32-bit explicit:\n";
$mykey = new Win32::TieRegistry
'HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Uninstall',
{ Access=>Win32::TieRegistry::KEY_READ()|0x0200, Delimiter=>'/' };
print "\tValues are:\n\t\t";
print join("\n\t\t", $mykey->ValueNames);
print "\n";
#Getting a specific value's value
#$mykeyval = $mykey->GetValue('Path');
print "\tFiltered subkeys are:\n\t\t";
print join("\n\t\t", grep(!/\{[-A-Fa-f0-9]+\}/, $mykey->SubKeyNames));
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 it is possible this could be prettier. But it works!
(Adapted from my solution to my question about not being able to read the registry, asked before I knew my problem was related to 64-bit vs. 32-bit).
精彩评论