如何从32位进程读取64位注册表项?

时间:2012-02-02 22:34:23

标签: windows delphi registry 64-bit 32bit-64bit

我一直在使用来自MachineGuid的密钥HKEY_LOCAL_MACHINE\Software\Microsoft\Cryptography的值来唯一标识主机,但是在64位计算机上运行的32位进程中,该值似乎缺失。我猜它正在Wow6432Node下搜索,它确实缺失了。根据{{​​3}},您能够通过添加标记来获取正确的密钥,但是代码下方似乎仍无法执行此任务。我错过了什么?

const
  KEY_WOW64_64KEY=$0100;
var
  r:HKEY;
  s:string;
  i,l:integer;
begin
  //use cryptography machineguid, keep a local copy of this in initialization?
  l:=40;
  if RegOpenKeyEx(HKEY_LOCAL_MACHINE,PChar('Software\Microsoft\Cryptography'),
    0,KEY_QUERY_VALUE,r)=ERROR_SUCCESS then
   begin
    SetLength(s,l);
    if RegQueryValue(r,'MachineGuid',PChar(s),l)=ERROR_SUCCESS then
     begin
      SetLength(s,l);
      RegCloseKey(r);
     end
    else
     begin
      //try from-32-to-64
      RegCloseKey(r);
      if RegOpenKeyEx(HKEY_LOCAL_MACHINE,PChar('Software\Microsoft\Cryptography'),
        0,KEY_QUERY_VALUE or KEY_WOW64_64KEY,r)=ERROR_SUCCESS then
       begin
        l:=40;
        if RegQueryValue(r,'MachineGuid',PChar(s),l)=ERROR_SUCCESS then
          SetLength(s,l)
        else
          l:=0;
        RegCloseKey(r);
       end;
     end;
   end;

4 个答案:

答案 0 :(得分:10)

我建议您使用IsWow64Process()函数来了解何时是在64位操作系统上运行的32进程,然后仅在该特定条件下应用KEY_WOW64_64KEY标志。如果应用程序是32位操作系统上的32位进程,或64位操作系统上的64位进程,则不需要标记。

例如:

const 
  KEY_WOW64_64KEY = $0100; 
var 
  key: HKEY; 
  str: string; 
  len: DWORD; 
  flag: REGSAM;
  wow64: BOOL;
begin 
  flag := 0;
  wow64 := 0;
  IsWow64Process(GetCurrentProcess(), @wow64);
  if wow64 <> 0 then flag := KEY_WOW64_64KEY;

  if RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Cryptography', 0, KEY_QUERY_VALUE or flag, key) = ERROR_SUCCESS then 
  try
    SetLength(str, 40); 
    len := Length(str) * SizeOf(Char); 
    if RegQueryValueEx(key, 'MachineGuid', nil, nil, PByte(Pointer(s)), @len) <> ERROR_SUCCESS then len := 0;
    SetLength(str, len div SizeOf(Char)); 
  finally
    RegCloseKey(key); 
  end; 
end;

答案 1 :(得分:7)

您的代码是不必要的复杂,主要是因为您没有利用内置的TRegistry类来保护您免受低级注册表API的所有复杂性的影响。例如,请考虑以下代码:

type
  TRegistryView = (rvDefault, rvRegistry64, rvRegistry32);

function RegistryViewAccessFlag(View: TRegistryView): LongWord;
begin
  case View of
  rvDefault:
    Result := 0;
  rvRegistry64:
    Result := KEY_WOW64_64KEY;
  rvRegistry32:
    Result := KEY_WOW64_32KEY;
  end;
end;

function ReadRegStr(const Root: HKEY; const Key, Name: string;
  const View: TRegistryView=rvDefault): string;
var
  Registry: TRegistry;
begin
  Registry := TRegistry.Create(KEY_READ or RegistryViewAccessFlag(View));
  try
    Registry.RootKey := Root;
    if not Registry.OpenKey(Key) then
      raise ERegistryException.CreateFmt('Key not found: %s', [Key]);
    if not Registry.ValueExists(Name) then
      raise ERegistryException.CreateFmt('Name not found: %s\%s', [Key, Name]);
    Result := Registry.ReadString(Name);//will raise exception in case of failure
  finally
    Registry.Free;
  end;
end;

函数ReadRegStr将从密钥Name返回相对于根密钥Key的名为Root的字符串值。如果存在错误,例如,如果密钥或名称不存在,或者该值的类型错误,则会引发异常。

View参数是一个枚举,使您可以轻松访问注册表的本机,32位或64位视图。请注意,native表示正在运行的进程的本机。因此,对于32位进程,它将是32位视图,对于64位进程,它将是64位视图。此枚举反映了.net中的等效定义。

答案 2 :(得分:4)

在我使用这个注册表项时,我更进了一步。如果该值不存在,我创建它:不在HKEY_LOCAL_MACHINE中,这需要提升,但在HKEY_CURRENT_USER中。任何看到引入密钥的人都不太可能意识到它是假的。

function GetComputerGUID: String;
var
  Reg: TRegistry;
  oGuid: TGUID;
  sGuid: String;
begin
  Result := '';
  // Attempt to retrieve the real key
  Reg := TRegistry.Create(KEY_READ OR KEY_WOW64_64KEY);
  try
    Reg.RootKey := HKEY_LOCAL_MACHINE;
    if Reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Cryptography') and Reg.ValueExists('MachineGuid') then
      Result := Reg.ReadString('MachineGuid');
    Reg.CloseKey;
  finally
    Reg.Free;
  end;
  // If retrieval fails, look for the surrogate
  if Result = '' then begin
    Reg := TRegistry.Create;
    try
      Reg.RootKey := HKEY_CURRENT_USER;
      if Reg.OpenKey('SOFTWARE\Microsoft\Cryptography', True) then begin
        if Reg.ValueExists('MachineGuid') then
          Result := Reg.ReadString('MachineGuid')
        else begin
          // If the surrogate doesn't exist, create it
          if CreateGUID(oGUID) = 0 then begin
            sGuid := Lowercase(GUIDToString(oGUID));
            Reg.WriteString('MachineGuid', Copy(sGuid, 2, Length(sGUID) - 2));
            Result := Reg.ReadString('MachineGuid');
          end;
        end;
      end;
      Reg.CloseKey;
    finally
      Reg.Free;
    end;
  end;
  if Result = '' then
    raise Exception.Create('Unable to access registry value in GetComputerGUID');
end;

这是@Remy Lebeau - TeamB的一个好点;我应该适当地修改上面的代码。

答案 3 :(得分:0)

使用此路径调用reg.exe C:\ WINDOWS \ sysnative \ REG.EXE 例如:

C:\Windows\sysnative\reg.exe QUERY "HKLM\SOFTWARE\JavaSoft\JDK" /v CurrentVersion

来源:https://stackoverflow.com/a/25103599