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

Greetings Monks,

I am running Strawberry Perl 5.24 on Windows 10. I have a question about Win32::TieRegistry. I am trying to use it to get information about a machine's processors. Based on my understanding of the documentation, I should be able to get it with this:

use Win32::TieRegistry(Delimiter=>'/'); my $idval = $Registry->{"HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/Syste +m/CentralProcessor/0//Identifier"};
But it seems that nothing gets put in $idval. An attempt to print its value results in:
Use of uninitialized value $idval in concatenation (.) or string at C: +\Users\ ... \TieRegistry.pl line 9.
It seems that hashes are not being tied to each level of the registry. Printing the keys and values of $Registry produces the following:
Key: CConfig/ Value: Win32::TieRegistry=HASH(0x2a184b4) Key: CUser/ Value: Win32::TieRegistry=HASH(0x2a1834c) Key: Classes/ Value: Win32::TieRegistry=HASH(0x2a189ac) Key: DynData/ Value: Key: LMachine/ Value: Win32::TieRegistry=HASH(0x2f8d7ec) Key: PerfData/ Value: Key: Users/ Value: Win32::TieRegistry=HASH(0x2f8d1ec)
As I would expect, hash references are associated with most keys. But printing the keys and values of $Registry->{"HKEY_LOCAL_MACHINE"} produces this:
Key: BCD00000000/ Value: Key: DRIVERS/ Value: Key: HARDWARE/ Value: Key: SAM/ Value: Key: SECURITY/ Value: Key: SOFTWARE/ Value: Key: SYSTEM/ Value:
The keys look right, but no hash references. Any ideas as to what's going on? Please help.

Here is my program (with 'use warnings' commented out to reduce clutter in the output):

use strict; # use warnings; use Win32::TieRegistry(Delimiter=>'/'); my ($idval, $k1); $idval = $Registry->{"HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System/C +entralProcessor/0//Identifier"}; print "IDVAL: $idval\n"; $k1 = $Registry; print "\nregistry top level - $k1\n"; PrintHash($k1); $k1 = $Registry->{"HKEY_LOCAL_MACHINE"}; print "\nHKEY_LOCAL_MACHINE - $k1\n"; PrintHash($k1); $k1 = $Registry->{"HKEY_LOCAL_MACHINE/HARDWARE"}; print "\n$k1\n"; PrintHash($k1); sub PrintHash { my ($hashref, $indent) = @_; my %hash = %{$hashref}; $indent += 2; my $maxsize = 0; foreach my $key (keys %hash) { $maxsize = length $key if (length $key > $maxsize); } foreach my $key (sort keys %hash) { printf "%*sKey: %-*s Value: %s\n", $indent, "", $maxsize, $key +, $hash{$key}; if (ref $hash{$key} eq 'ARRAY') { PrintArray($hash{$key}, $ind +ent); } if (ref $hash{$key} eq 'HASH') { PrintHash($hash{$key}, $inde +nt); } } } sub PrintArray { my ($array, $indent) = @_; my @arr = @{$array}; $indent += 2; my $cnt = 0; foreach my $elem (@arr) { printf("%*s%2d. %s\n", $indent, "", $cnt, $elem); if (ref $elem eq 'ARRAY') { PrintArray($elem, $indent); } if (ref $elem eq 'HASH') { PrintHash($elem, $indent); } ++$cnt; } }
Here is the output I get:
IDVAL: registry top level - Win32::TieRegistry=HASH(0x2a993bc) Key: CConfig/ Value: Win32::TieRegistry=HASH(0x2a184b4) Key: CUser/ Value: Win32::TieRegistry=HASH(0x2a1834c) Key: Classes/ Value: Win32::TieRegistry=HASH(0x2a189ac) Key: DynData/ Value: Key: LMachine/ Value: Win32::TieRegistry=HASH(0x2f8d7ec) Key: PerfData/ Value: Key: Users/ Value: Win32::TieRegistry=HASH(0x2f8d1ec) HKEY_LOCAL_MACHINE - Win32::TieRegistry=HASH(0x2f8d1d4) Key: BCD00000000/ Value: Key: DRIVERS/ Value: Key: HARDWARE/ Value: Key: SAM/ Value: Key: SECURITY/ Value: Key: SOFTWARE/ Value: Key: SYSTEM/ Value: Can't use an undefined value as a HASH reference at C:\Users\James\Por +table\strawberry-perl-5.24.0.1-32bit-portable\Perl Source\TieRegistry +.pl line 28.

Replies are listed 'Best First'.
Re: Need help with Win32::TieRegistry
by Discipulus (Canon) on Jul 01, 2019 at 07:38 UTC
    Hello CrashBlossom,

    you need administrative rights to fetch this (be also aware, not this case, of Registry Redirection: search it in my bibliotheca)

    perl -MData::Dump -MWin32 -e " print Win32::IsAdminUser()?qq(ADMIN\n):qq(NOT admin\n); use Win32::TieRegistry(Delimiter=>'/'); my $idval = $Registry->'HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System +/CentralProcessor/0'}; dd $idval " NOT admin undef #launched portableshell.bat as administrator: perl -MData::Dump -MWin32 -e " print Win32::IsAdminUser()?qq(ADMIN\n):qq(NOT admin\n); use Win32::TieRegistry(Delimiter=>'/'); my $idval = $Registry->'HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System +/CentralProcessor/0'}; dd $idval " ADMIN bless({ # tied Win32::TieRegistry "/Component Information" => "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", "/Configuration Data" => pack("H*","ffffffffffffffff000000000 +0000000"), "/FeatureSet" => "0x3D1B3FFF", "/Identifier" => "Intel64 Family 6 Model 94 Stepping +3", "/Platform Specific Field 1" => "0x00000002", "/Previous Update Revision" => "\0\0\0\0\xA0\0\0\0", "/ProcessorNameString" => "Intel(R) Core(TM) i5-6400 CPU \@ 2. +70GHz", "/Update Revision" => "\0\0\0\0\xC6\0\0\0", "/Update Status" => "0x00000000", "/VendorIdentifier" => "GenuineIntel", "/~MHz" => "0x00000A98", }, "Win32::TieRegistry")

    L*

    PS you also have a (not influencing results) double delimiter in /0//Identifier

    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.
      you need administrative rights to fetch this
      Do you? Win32::SystemInfo works with user privileges. And the module is reading from the Registry too. Addendum: It is using a combination of Win32::TieRegistry and the GetSystemInfo function from Win32::API. Here's the relevant function.
      use Win32::SystemInfo; use Data::Dumper; my %phash; Win32::SystemInfo::ProcessorInfo(%phash); print Dumper (\%phash);
      Yields on my system, running as normal user:
      $VAR1 = { 'Processor3' => { 'Identifier' => 'Intel64 Family 6 Model 60 + Stepping 3', 'ProcessorName' => 'Intel(R) Core(TM) i5-4 +440 CPU @ 3.10GHz', 'VendorIdentifier' => 'GenuineIntel', 'MHZ' => 3093 }, 'NumProcessors' => 4, 'Processor2' => { 'MHZ' => 3093, 'VendorIdentifier' => 'GenuineIntel', 'Identifier' => 'Intel64 Family 6 Model 60 + Stepping 3', 'ProcessorName' => 'Intel(R) Core(TM) i5-4 +440 CPU @ 3.10GHz' }, 'Processor0' => { 'MHZ' => 3093, 'VendorIdentifier' => 'GenuineIntel', 'ProcessorName' => 'Intel(R) Core(TM) i5-4 +440 CPU @ 3.10GHz', 'Identifier' => 'Intel64 Family 6 Model 60 + Stepping 3' }, 'Processor1' => { 'ProcessorName' => 'Intel(R) Core(TM) i5-4 +440 CPU @ 3.10GHz', 'Identifier' => 'Intel64 Family 6 Model 60 + Stepping 3', 'VendorIdentifier' => 'GenuineIntel', 'MHZ' => 3093 } };


      holli

      You can lead your users to water, but alas, you cannot drown them.
        After reading holli's observation that SystemInfo uses TieRegistry, I took look at the source for SystemInfo. The following bit at the top is lifted almost verbatim from SystemInfo:
        use strict; use warnings; use Win32::TieRegistry qw(:KEY_); $Registry->Delimiter("/"); my $procinfo = $Registry->Open( "HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System/Centra +lProcessor/0", { Access => KEY_READ() } ); PrintHash($procinfo); sub PrintHash { my ($hashref, $indent) = @_; my %hash = %{$hashref}; $indent += 2; my $maxsize = 0; foreach my $key (keys %hash) { $maxsize = length $key if (length $key > $maxsize); } foreach my $key (sort keys %hash) { printf "%*sKey: %-*s Value: %s\n", $indent, "", $maxsize, $key +, $hash{$key}; if (ref $hash{$key} eq 'ARRAY') { PrintArray($hash{$key}, $ind +ent); } if (ref $hash{$key} eq 'HASH') { PrintHash($hash{$key}, $inde +nt); } } } sub PrintArray { my ($array, $indent) = @_; my @arr = @{$array}; $indent += 2; my $cnt = 0; foreach my $elem (@arr) { printf("%*s%2d. %s\n", $indent, "", $cnt, $elem); if (ref $elem eq 'ARRAY') { PrintArray($elem, $indent); } if (ref $elem eq 'HASH') { PrintHash($elem, $indent); } ++$cnt; } }
        Here is the result:
        Key: /Component Information Value: Key: /Configuration Data Value:          Key: /FeatureSet Value: 0x3D1B3FFF Key: /Identifier Value: Intel64 Family 6 Model 60 Ste +pping 3 Key: /Platform Specific Field 1 Value: 0x00000020 Key: /Previous Update Revision Value:  Key: /ProcessorNameString Value: Intel(R) Core(TM) i7-4700HQ C +PU @ 2.40GHz Key: /Update Revision Value: % Key: /Update Status Value: 0x00000000 Key: /VendorIdentifier Value: GenuineIntel Key: /~MHz Value: 0x0000095A

        Apparently "Access => KEY_READ()" indicates that read-only access is requested, which makes everything good.

        Thanks for the responses. This issue is resolved

        I suppose TieRegistry requires admin rights because it allows you to change the registry. In any case, SystemInfo provides the information I need for this particular problem, so thanks for the tip!