从Perl中的Windows注册表中读取

时间:2015-05-15 22:56:17

标签: windows perl registry

我正在尝试获取程序的安装位置而不检查一系列硬编码路径,希望从Windows注册表中存储的路径中获取它,但是当我尝试时,我得到空的返回值或错误消息读取所需的键值。

我已经阅读了Parsing windows registry using Perl,我认为我已将所有答案合并到我的脚本中,但是当我尝试读取注册表值时,即使从高架上运行,我总是得到一个空的结果命令提示符以确保脚本具有管理员权限。

我首先尝试使用Win32 :: TieRegistry,并且如前所述,返回的值为空,所以我尝试使用reg query进行shelling,但这会导致关于找不到密钥的错误。在Perl之外运行相同的reg query命令成功读取密钥。我做错了什么?

更新:根本原因(我收到的几个答案中指出)试图access a 64-bit registry view from a 32-bit Perl;默认情况下,Windows中的任何32位应用程序在尝试访问HKLM\Software\WOW6432Node密钥时都会重定向到HKLM\Software,因此我需要找到一种方法来避免这种情况,因为我感兴趣的密钥不存在于该位置

Perl脚本:

#!/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";

输出:

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=
在Perl之外的

手动reg query命令:

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

注意,所有这些都是从提升的命令提示符开始运行的;一旦它在那里工作,我将试验是否有必要。

2 个答案:

答案 0 :(得分:2)

你使用的是64位操作系统和32位perl 这意味着当从perl运行时,你实际上得到的是WOW6432Node中的值而不是你想要的键

你需要使用64位perl。

例如来自我自己的机器

λ c:\Strawberry\perl\bin\perl
my $sysCmd = `reg query  "HKLM\\SOFTWARE\\VMware, Inc.\\VMware Drivers" /v vmci.status`;
print $sysCmd;
^D
ERROR: The system was unable to find the specified registry key or value.

λ c:\Strawberry\perl\bin\perl
my $sysCmd = `reg query "HKLM\\SOFTWARE\\VMware, Inc.\\VMware USB" /v InstallPath`;
print $sysCmd;
^D

HKEY_LOCAL_MACHINE\SOFTWARE\VMware, Inc.\VMware USB
    InstallPath    REG_SZ    C:\Program Files (x86)\Common Files\VMware\USB\

其中“HKEY_LOCAL_MACHINE \ SOFTWARE \ VMware,Inc。\ VMware USB”位于WOW6432Node中且驱动程序不在。

这会影响从perl运行的命令和模块。

[为了完整起见而编辑] 显然有一种方法可以从32位perl获取64位密钥,如http://www.perlmonks.org/?node_id=1007098讨论底部所示

答案 1 :(得分:2)

正如Srgrn的回答中所提到的,问题源于我的Perl是32位,运行在64位系统上。在访问HKLM\Software时,Windows会自动将32位进程重定向到Wow6432Node注册表节点,除非明确告知use 64-bit or 32-bit registry views with an access mode flag

我可以specify access with the old Win32API::Registry,但我选择使用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";

这给出了32位和64位密钥的预期结果,并且在32位和64位Perl中也应该以相同的方式工作(理论上无论如何)。

注意:我需要在我的Perl版本中为KEY_READ()函数指定完整的命名空间以防止编译错误,并且我不确定是否有0x0100和0x0200常量的命名值,所以这个在某些系统上可能比需要的更粗糙,但它似乎对我很有用!

注意:这也允许你read the right version of a key with the same name in either 32-bit and 64-bit,所以这个答案在那里重复。

相关问题