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?
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);
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;
{-----------}
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;
You should using this:
TRegistry.Create(KEY_ENUMERATE_SUB_KEYS);
windows seven UAC won't prevent executing this
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.
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.