Registry ReadString method is not working in Windo

2019-02-17 10:45发布

问题:

The following code sample used to return me windows id before, but now it doesn't work, and returns empty string, dunno why.

  function GetWindowsID: string;
  var
    Registry: TRegistry;
    str:string;
  begin
    Registry := TRegistry.Create(KEY_WRITE);
    try
      Registry.Lazywrite := false;
      Registry.RootKey := HKEY_LOCAL_MACHINE;
   //   Registry.RootKey := HKEY_CURRENT_USER;
      if CheckForWinNT = true then
       Begin
       if not Registry.OpenKeyReadOnly('\Software\Microsoft\Windows NT\CurrentVersion') then showmessagE('cant open');
       end
      else
        Registry.OpenKeyReadOnly('\Software\Microsoft\Windows\CurrentVersion');
      str := Registry.ReadString('ProductId');
      result:=str;
      Registry.CloseKey;
    finally
      Registry.Free;
    end; // try..finally
  end;

Anybody can help?

回答1:

That is because the virtualized key '\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\' doesn't contain the 'ProductID' item.

Modify your code to create the TRegistry instance with

Registry := TRegistry.Create(KEY_WRITE OR KEY_WOW64_64KEY);

where KEY_WOW64_64KEY = $0100. That will give you the expected result.

Alternatively, use DSiWin32 and call

DSiReadRegistry('\Software\Microsoft\Windows NT\CurrentVersion', 
  'ProductID', '', HKEY_LOCAL_MACHINE, KEY_QUERY_VALUE OR KEY_WOW64_64KEY);


回答2:

There are usefull procedure to read Key Register in a 32 bit and 64 bit enviroment.First look what system you have

Type TTypWin32Or64 = (Bit32,Bit64);
var TypWin32Or64 :TTypWin32Or64;

 Procedure TypeOS(var TypWin32Or64:TTypWin32Or64 ) ;
   if DirectoryExists('c:\Windows\SysWOW64')
     then TypWin32Or64:=Bit64
     else TypWin32Or64:=Bit32;

  Procedure for looking Key or Create it in a Registry
   procedure TForm1.ReadKeyFromRegister(TypWin32Or64:TTypWin32Or64;
                       TypeKey:Longword; {at once symbol HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER}
                       PathToKey:string;
                       TypeValueRead :Integer; //at once symbols as REG_SZ -- string key ,
                          //REG_DWORD A DWORD value, a 32-bit unsigned integer
                       NameValueToRead:string;
                       var ValueStrReaded:Ansistring; //is used if it is key string
                       var ValueByteReaded:Pchar; //is used if it is key Byte
                       ReadOnly:boolean);  
var
  Reg       : TRegistry;
  S_TStr    : TStrings;
  VersBios  : string;
  Pos0      : integer;
  Key       : HKEY;
  Value     : Array of Byte;
  nValueLen :  Integer;
const KEY_WOW64_64KEY = $0100 ;
 begin
  case TypWin32Or64 of
    Bit32: Reg := TRegistry.Create;
    Bit64:Reg := TRegistry.Create(KEY_WRITE OR KEY_WOW64_64KEY); 
    //use if if 64 bit enviroment Windows 
  end;
 try
  { open key }
   Reg.RootKey := TypeKey;
   if ReadOnly
     then Reg.OpenKeyReadOnly(PathToKey) 
        //not all key can be created or writed ie. ProductId(Serial Key)
        // name Windows - especially in a 64 bit Windows XP , Win 7  
     else Reg.OpenKey(PathToKey, false); 
        //CreateKey=True--> if this key is not present will be created
    case TypeValueRead of
     REG_SZ: ValueStrReaded:=Reg.ReadString(NameValueToRead);
     REG_BINARY : begin
                   nValueLen := Reg.GetDataSize(NameValueToRead);
                   ValueByteReaded:=Pchar(Reg.ReadBinaryData(NameValueToRead, PByte(Value), nValueLen));
                end;
     REG_DWORD : begin

                 end;
     REG_MULTI_SZ: begin
                    S_TStr := ReadMultirowKey(Reg,NameValueToRead);
                       /in a enviroment 64 bit not good work - better use       
                       //procedure ReadREG_MULTI_SZ
                     VersBios:=S_TStr.Text;
                     Pos0:=Pos(#0,VersBios);
                     if Pos0 > 0  then
                       begin
                        delete(VersBios,Pos0,1);
                        insert(' ', VersBios,Pos0);
                       end;
                     VersBios := StringReplace(VersBios,#$D#$A, ' ' , [rfReplaceAll, rfIgnoreCase]);
                   ValueStrReaded:=VersBios;
                 end;
      end;  //case
      Reg.CloseKey;
   finally
    Reg.Free;
  end;
end;
{------------}

 Sample for reading system Key from Registry
   Reading UsedWindowsVersion_Full
     ReadKeyFromRegister(TypWin32Or64, {TypWin32Or64}
                  HKEY_LOCAL_MACHINE, {TypeKey:Longword;}
                  'SOFTWARE\Microsoft\Windows NT\CurrentVersion', {PathToKey:string;}
                          REG_SZ, {TypeValueRead :Integer; }
                          'BuildLabEx', {NameValueToRead:string;}
                          UsedWindowsVersion_Full, {ValueStrReaded:Ansistring;}
                          sPchar ,{ValueByteReaded:Pchar}
                          True {ReadOnly});
            {-----------------------}   

      For read ProductId(also called Product Key Windows)
           ReadKeyFromRegister( TypWin32Or64,
                   HKEY_LOCAL_MACHINE, {TypeKey:Longword;}
                  'SOFTWARE\Microsoft\Windows NT\CurrentVersion', {PathToKey:string;}
                          REG_SZ, {TypeValueRead :Integer; }
                          'ProductId', {NameValueToRead:string;}
                          SerialKey, {ValueStrReaded:Ansistring;}
                          sPchar, {ValueByteReaded:Pchar}
                          True {ReadOnly});
             {------------------------}   
     For reading Product Name
         ReadKeyFromRegister(TypWin32Or64,
                  HKEY_LOCAL_MACHINE, {TypeKey:Longword;}
                  'SOFTWARE\Microsoft\Windows NT\CurrentVersion', {PathToKey:string;}
                          REG_SZ, {TypeValueRead :Integer; }
                          'ProductName', {NameValueToRead:string;}
                          UsedWindowsName, {ValueStrReaded:Ansistring;}
                          sPchar ,{ValueByteReaded:Pchar}
                          True {ReadOnly});   
           {-----------------------}
  Procedure for look miltiline key as i.e Version Bios - also 64 envir.

     procedure  TForm1.ReadREG_MULTI_SZ(const CurrentKey: HKey; const   
                                   Subkey, ValueName: string;
                                   Strings: TStrings; var ValueStrRead: String);
       var
         valueType: DWORD;
         valueLen: DWORD;
         p, buffer: PChar;
         key: HKEY;
        begin
         Strings.Clear;
           // open the specified key
       if RegOpenKeyEx(CurrentKey,
              PChar(Subkey),
              0, KEY_READ, key) = ERROR_SUCCESS then
          begin
            // retrieve the type and data for a specified value name
            SetLastError(RegQueryValueEx(key,
             PChar(ValueName),
             nil,
             @valueType,
             nil,
             @valueLen));
             if GetLastError = ERROR_SUCCESS then
                if valueType = REG_MULTI_SZ then
                  begin
                   GetMem(buffer, valueLen);
                   try
                    // receive the value's data (in an array).
                    RegQueryValueEx(key,
                                    PChar(ValueName),
                                    nil,
                                    nil,
                                    PBYTE(buffer),
                                    @valueLen);
                     // Add values to stringlist
                     p := buffer;
                     while p^ <> #0 do
                        begin
                         Strings.Add(p);
                         Inc(p, lstrlen(p) + 1)
                        end
                    finally
                      ValueStrRead:=Strings.Text;
                      ValueStrRead:=StringReplace(ValueStrRead,#$D#$A, ' ' , [rfReplaceAll, rfIgnoreCase]);
                      FreeMem(buffer);
                     end
                   end
                else
                 raise ERegistryException.Create('Stringlist expected')
                  else
                   raise ERegistryException.Create('Cannot Read MULTI_SZ    Value/');
           end;
        end;
      {-----------}     


回答3:

I'd say that this is caused by UAC - try starting as administrator!

If it works when started as administrator, then you need to change your read request to use read only mode (not at desk at mo so can't remember exactly how you do that)

edit:

function GetWindowsID: string; 
var 
  Registry: TRegistry; 
  str:string; 
begin 
  Registry := TRegistry.Create(KEY_READ); 
  try 
    Registry.RootKey := HKEY_LOCAL_MACHINE; 
 //   Registry.RootKey := HKEY_CURRENT_USER; 
    if CheckForWinNT = true then 
     Begin 
     if not Registry.OpenKeyReadOnly('\Software\Microsoft\Windows NT\CurrentVersion') then showmessage('cant open'); 
     end else 
       Registry.OpenKeyReadOnly('\Software\Microsoft\Windows\CurrentVersion'); 
    str := Registry.ReadString('ProductId'); 
    result:=str; 
    Registry.CloseKey; 
  finally 
    Registry.Free; 
  end; // try..finally 
end; 


回答4:

You should using this: TRegistry.Create(KEY_ENUMERATE_SUB_KEYS); windows seven UAC won't prevent executing this



回答5:

Try reading it manually using RegEdit. You may get 'Access Denied' due to a permission issue, in which case look at your level and how you are accessing it.



回答6:

I believe it's because

str := Registry.ReadString('ProductId');

does not raise an exception when there is no ProductId. In my honest opinion, this is a bug in Delphi.