Registry ReadString method is not working in Windows 7 in Delphi 7

30,984

Solution 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);

Solution 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;
      {-----------}     

Solution 3

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

Solution 4

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; 
Share:
30,984
Tofig Hasanov
Author by

Tofig Hasanov

My main area of interest is Computer Science; however, I have also spent at least several years studying and practicing each of the following fields: 1) Psychology - particularly psychoanalysis, group dynamics and psychology of masses 2) Philosophy - Mostly interested in practical aspects, such as dialectical logic 3) Personal Development - Some might not classify it as a separate field of study, but I have spent more than 10 years doing research and consulting in this area and I know how deep and fascinating this field is. 4) Business Management - Systems and Control theory. Spent a lot of time working on startups as well. 5) Education - Tought Machine Learning, Algorithms and Data Structures and Engineering Design classes to undergraduate students in Qafqaz University. 6) Gaming - I have played lots of games, and I have studied them as well. I believe that we can borrow a lot of tricks from successful games, especially in the area of motivation, and implement them in education and other areas. As for computer science itself, my main focus is Machine Learning, Multi-Agent Systems and Crowdsourcing. It might seem that all these subjects are completely unrelated, but they are all united in the goal to understand various aspects of human mind: how we think, how we learn, how we motivate ourselves, etc. This is what excites me most. I think that to make the world a better place, we should start with understanding and improving ourselves.

Updated on July 16, 2022

Comments

  • Tofig Hasanov
    Tofig Hasanov almost 2 years

    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?