5

Windows

With Raku/Perl6, how do I use NativeCall to read the value of

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ "EnableLUA"]

with RegQueryValueExW?

https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw

Many thanks,

-T

edit 12-27-2019 #1: removing bad code and inserting new code

This is how far I have gotten.

Test run string: K:\Windows\NtUtil>perl6 -I. -e "use WinMount :GetLUA; say GetLUA();" RegOpenKeyExW RegOpenKeyExW RtnCode 0

RegQueryValueExW
1
2
RegQueryValueExW   RtnCode 87  (87 = ERROR_INVALID_PARAMETER)
lpData pointer 0
lpcbData data length 0

RegCloseKey
RegCloseKey   RtnCode 0

True

WinMount.pm6

# unit module WinMount;
# WinMount.pm6#`{

   Utilities to mount and dismound drive partitions
   Note: LUA must be unset (0x00000000) for mount to function prpoperly 

   raku -I. -c WinMount.pm6

}

use NativeCall;
use WinPopUps :WinMsg;


# Reference to types and values: http://dsource.org/projects/tango/ticket/820

constant BYTE    := uint8;
constant WCHAR   := uint16;   
constant DWORD   := int32;    
constant REGSAM  := int32;
constant WCHARS  := CArray[WCHAR];
constant BYTES   := CArray[BYTE];

constant HKEY_CURRENT_USER  = 0x80000001;
constant HKEY_LOCAL_MACHINE = 0x80000002;
constant KEY_QUERY_VALUE   = 1;
constant ERROR_SUCCESS     = 0; # Yeah, I know. The Win-Api uses 0 for success and other values to indicate errors
constant REG_SZ = 1;

constant KEY_READ      = 0x20019;
constant KEY_SET_VALUE = 0x0002;
constant REG_DWORD     = 0x00000004;



sub to-c-str( Str $str ) returns CArray[WCHAR]  is export( :to-c-str ) {
   my @str := CArray[WCHAR].new;
   for ( $str.comb ).kv -> $i, $char { @str[$i] = $char.ord; }
   @str[ $str.chars ] = 0;
   @str;
}


sub wstr( Str $str ) returns WCHARS  is export( :wstr ) {
    CArray[WCHAR].new( $str.comb.map: *.ord )
}


sub GetLUA() is export( :GetLUA ) {

#`{

Returns the LUA value in the registry to True (0x00000001) or False (0x00000000)

          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
          "EnableLUA"=dword:00000000

    https://docs.perl6.org/language/nativecall

    Win32 return codes:
    https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-

}

   my Str $SubName = &?ROUTINE.name;
   my Str $OS      = $*KERNEL.name;
   if not $OS eq "win32" { say "Sorry, $SubName only work in Windows."; exit; }

   my Bool  $LUA = True;
   my       $RtnCode;

   my Str   $SubKey = Q[SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\];
   my Str   $Key = Q[EnableLUA];

   my       $lpSubKey    = wstr( $SubKey );
   my       $lpValueName = wstr( $Key );
   # my $lpSubKey    = CArray[uint8].new($Key.encode.list);
   # my $lpValueName = CArray[uint8].new($SubKey.encode.list);


   my int32 $Handle;
   my int32 $ulOptions = 0;
   my int32 $lpData;
   my int32 $lpcbData;
   my int32 $lpReserved = 1;


#`{
    Open the key:
    https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regopenkeyexw
    https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-key-security-and-access-rights
    C++
    LSTATUS RegOpenKeyExW(
       HKEY    hKey,          # Hive name (HKEY_LOCAL_MACHINE)
       LPCWSTR lpSubKey,      # path to the key(/SOFTWARE/Microsoft/Windows/CurrentVersion/Policies/System/EnableLUA)
       DWORD   ulOptions,     # 0
       REGSAM  samDesired,    # KEY_READ (0x20019), KEY_SET_VALUE (0x0002)
       PHKEY   phkResult      # A pointer to a variable that receives a handle to the opened key
    );
}    
   say "RegOpenKeyExW";
   sub RegOpenKeyExW( DWORD, WCHARS, DWORD, DWORD, DWORD is rw) is native("Kernel32.dll") returns DWORD { * };
   $RtnCode = RegOpenKeyExW( HKEY_LOCAL_MACHINE, $lpSubKey, $ulOptions, KEY_READ, $Handle );
   say "RegOpenKeyExW   RtnCode $RtnCode\n";



#`{
    Read the key:
    use RegQueryValueExW if you know key and value name
    https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw
    C++
    LSTATUS RegQueryValueExW(
       HKEY    hKey,          # Hive name (HKEY_LOCAL_MACHINE)
       LPCWSTR lpValueName,   # path to the key(\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA)
       LPDWORD lpReserved,    # give it "int32" without the quotes to give it a NULL
       LPDWORD lpType,        # Registry Value Type (REG_DWORD which is 32 bit)
       LPBYTE  lpData,        # Pointer to the return value
       LPDWORD lpcbData       # number of bytes in the return value
    );
}    
   say "RegQueryValueExW";
   sub RegQueryValueExW( DWORD, WCHARS, DWORD, DWORD, DWORD is rw, DWORD is rw ) is native("Kernel32.dll") returns DWORD { * };
say "1";   
   $RtnCode = RegQueryValueExW( $Handle, $lpValueName, $lpReserved, REG_DWORD, $lpData, $lpcbData );
say "2";   
   say "RegQueryValueExW   RtnCode $RtnCode  (87 = ERROR_INVALID_PARAMETER)\nlpData pointer $lpData\nlpcbData data length $lpcbData\n";



#`{
    Close the key 
    https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
    C++
    LSTATUS RegCloseKey(
       HKEY hKey    # handle to the open key to be closed.  See RegOpenKeyExW phkResult
    );
}   
   say "RegCloseKey";
   sub RegCloseKey( DWORD ) is native("Kernel32.dll") returns DWORD { * };
   $RtnCode = RegCloseKey( $Handle );
   say "RegCloseKey   RtnCode $RtnCode\n";


   return $LUA;
}
Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
Todd
  • 976
  • 4
  • 10
  • 3
    NativeCall needs a native library to make a call. What library is used in Windows to read that registry key? – jjmerelo Dec 26 '19 at 08:12
  • 1
    Kernel32 would be the library – Todd Dec 26 '19 at 20:47
  • You can find `typedef`s and constants and more in the windows header files. Most of it in winnt.h/windows.h – Holli Dec 26 '19 at 21:35
  • You can find those files in the Windows SDK, but there are also various copies on github. – Holli Dec 26 '19 at 21:45
  • The listing is confusing. There seems to be the output of a program, as well as a program. Can you please divide the listing where it should be divided? – jjmerelo Dec 27 '19 at 11:06
  • 2
    Use [`RegGetValue`](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluew#return-value) is more simple: `RegGetValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", TEXT("EnableLUA"), RRF_RT_REG_DWORD, NULL, buf, &bufSize);` – Rita Han Dec 30 '19 at 03:20

1 Answers1

3

Here's what I have so far. I am able to successfully retrieve the handle for the registry key, but when I try to read the key it throws "Native call expected argument that references a native integer, but got P6int". And I don't know why yet. But I figured I post this already, maybe someone else can shed some light.

use NativeCall;

constant BYTE    := uint8;
constant WCHAR   := uint16;   
constant DWORD   := int32;    
constant REGSAM  := int32;
constant WCHARS  := CArray[WCHAR];
constant BYTES   := CArray[BYTE];

constant HKEY_CURRENT_USER  = 0x80000001;
constant HKEY_LOCAL_MACHINE = 0x80000002;
constant KEY_QUERY_VALUE   = 1;
constant ERROR_SUCCESS     = 0; # Yeah, I know. The Win-Api uses 0 for success and other values to indicate errors
constant REG_SZ = 1;

sub RegOpenKeyExW( DWORD, WCHARS, DWORD, REGSAM, DWORD is rw) is native("Kernel32.dll") returns DWORD { * };

#DWORD RegOpenKeyExW(
#  HKEY    hKey,
#  LPCWSTR lpSubKey,
#  DWORD   ulOptions,
#  REGSAM  samDesired,
#  PHKEY   phkResult
#);

sub RegQueryValueExW( DWORD, WCHARS, DWORD is rw, DWORD is rw, BYTE is rw, DWORD is rw) is native("Kernel32.dll") returns DWORD { * };

#DWORD RegQueryValueExW(
#  HKEY    hKey,
#  LPCWSTR lpValueName,
#  LPDWORD lpReserved,
#  LPDWORD lpType,
#  LPBYTE  lpData,
#  LPDWORD lpcbData
#);


my $key = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System';

my DWORD $hkey;
my $length = 1024;

if RegOpenKeyExW(HKEY_LOCAL_MACHINE, wstr($key), 0, KEY_QUERY_VALUE, $hkey) == ERROR_SUCCESS
{
    say "Got handle: $hkey";

    my BYTES $buffer = CArray[BYTE].new( 0 xx 1024 );

    # throws "Native call expected argument that references a native integer, but got P6int"
    if RegQueryValueExW( $hkey, WCHARS, DWORD, REG_SZ, $buffer, $length ) == ERROR_SUCCESS
    {
        say "Got data of length $length";
        say gather for 0 .. $length { take $buffer[$_] };
    }
}


sub wstr( Str $str ) returns WCHARS {
    CArray[WCHAR].new( $str.comb.map: *.ord )
}
Holli
  • 5,072
  • 10
  • 27
  • Hi Holli, see my addition to the original port – Todd Dec 26 '19 at 20:37
  • @Holli A google for ["Native call expected argument that references a native integer, but got P6int"](https://www.google.com/search?q=%22Native+call+expected+argument+that+references+a+native+integer%2C+but+got+P6int%22) leads to [an SO comment by JJ](https://stackoverflow.com/questions/50087913/native-localtime-segfaults#comment87193309_50088223) and follow up comments. Maybe they're illuminating? – raiph Dec 26 '19 at 22:11
  • @Holli A search for the error message in moarvm sources found nothing exactly matching, but [something notably close](https://github.com/MoarVM/MoarVM/blob/ee18678e91b8ba5afea6303ae517a4db0c15573e/src/core/nativecall_libffi.c#L454). A click on history led to the commit that changed the error message from what used to be [the exact match](https://github.com/MoarVM/MoarVM/commit/cfc5d00061f94d9af6a8a698ca72889de1a5d63a#diff-8265f8186b13f6fb56f0f9a352db9bab). So if you install a very recent Rakudo you'll presumably at least get a better error message. – raiph Dec 26 '19 at 22:12
  • K:\Windows\NtUtil>perl6 -v This is Rakudo Star version 2019.03.1 built on MoarVM version 2019.03 implementing Perl 6.d. – Todd Dec 26 '19 at 22:36
  • Hi Holli: Where did you find the values for constants. I only found: https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types – Todd Dec 27 '19 at 01:24
  • Hi Holli, I modified my original post with my new test code. – Todd Dec 27 '19 at 06:34
  • @Todd the post is quite confuding now. Can you please edit it to separate the listing from the result of running the program, and also link this answer where you found the code? – jjmerelo Dec 27 '19 at 11:07
  • any better? 123 – Todd Dec 27 '19 at 12:28
  • 1
    You didn't pass the value name "EnableLUA" to `RegQueryValueExW`. The `WCHARS` is not initialized. – Rita Han Dec 30 '19 at 02:59
  • your wstr sub does not tack a null chr(0) at the end – Todd Jan 01 '20 at 02:23
  • Hi All, I have solved this. It consists of three modules. I am not sure where the best place is to post several hundred line of code is. There is a forth and fifth that also deals with this, but they are still peculating – Todd Jan 01 '20 at 06:55
  • It will eventually find its way over here: https://www.nntp.perl.org/group/perl.perl6.users/2019/12/msg7572.html – Todd Jan 01 '20 at 07:10
  • Where is the final solution? I cannot find it. – StevieD Sep 03 '22 at 18:21