2012-02-02 181 views
8

我一直在使用來自HKEY_LOCAL_MACHINE\Software\Microsoft\Cryptography的密鑰MachineGuid的值來唯一標識主機,但是使用在64位計算機上運行的32位進程的值似乎丟失了。我想它是在Wow6432Node下搜索的,它確實缺少。根據this應該能夠通過添加一個標誌,以獲得正確的關鍵,但下面的代碼仍然沒有出現工作。我錯過了什麼?如何從32位進程讀取64位註冊表項?

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; 
+5

爲什麼不使用TRegistry?你的邏輯也是一團糟。你想要一個函數來調用來讀取值。稱它兩次。第一次通過0.第二次通過KEY_WOW64_64KEY。如果第一次失敗,只調用第二次。這是提取方法重構。 – 2012-02-02 22:59:26

+0

我之前使用過TRegistry,但並不知道你通過帶參數的構造函數添加KEY_WOW64_64KEY。 – 2012-02-03 10:02:32

+1

當然可以。看到我的答案。編輯:看起來你現在找到了我的答案。另請注意,您可以隨時修改'Access'屬性以在已創建的註冊表對象中切換視圖。 – 2012-02-03 10:07:41

回答

6

你的代碼是不必要的複雜的,主要是因爲你沒有利用內置的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將從關鍵Key相對於根密鑰Root返回命名爲Name字符串值。如果存在錯誤,例如,如果鍵或名稱不存在,或者值的類型錯誤,則會引發異常。

View參數是一個枚舉,它使您可以輕鬆訪問註冊表的原生32位或64位視圖。請注意,本機對於正在運行的進程來說是本機的。所以它將是32位視圖的32位視圖和64位過程的64位視圖。此枚舉映射.net中的等效定義。

+0

nope仍然不起作用,ReadString給出空字符串(這可能是我的筆記本電腦有問題嗎?):const KEY_WOW64_64KEY = $ 0100; var r:TRegistry; s:string; begin r:= TRegistry.Create(KEY_READ or KEY_WOW64_64KEY); r.RootKey:= HKEY_LOCAL_MACHINE; 如果r.OpenKeyReadOnly('Software \ Microsoft \ Cryptography')則 s:= r.ReadString('MachineGuid'); – 2012-02-03 18:08:11

+0

我的代碼中存在一個我剛剛修復的錯誤。 RootKey。但你已經知道了。你的代碼應該工作。那裏的鑰匙?!我會在一個小時左右檢查我的機器。晚餐時間在這裏! – 2012-02-03 18:27:31

+0

我測試了代碼。我修復了另一個bug,因爲我不明白'TRegistry'是如何工作的,當一個值不存在時。但是,如果你看到一個空字符串,那麼就會出現錯誤。我的代碼(和我的代碼)在運行時返回正確的值。我很想知道你的Delphi版本是什麼。也許你在一箇舊的Delphi上,「TRegistry」不尊重'KEY_WOW64_64KEY'。這會讓我感到驚訝。由於您正在定義'KEY_WOW64_64KEY',所以我對此有點懷疑,但我只是從Windows.pas中獲得它。那麼,你在用什麼德爾福? – 2012-02-03 19:31:36

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; 
+3

我認爲你可以簡單地總是應用該標誌,它在x86操作系統上被忽略 – Remko 2012-02-03 11:49:28

+1

正是如此。如果你總是想從原生視圖讀取,你可以無條件地使用'KEY_WOW64_64KEY' – 2014-05-22 15:25:35

+2

只有在XP和更高版本中才能識別64位系統的存在,即使在32位版本中也是如此。如果您在Win2k或更低版本上指定該標誌,它將作爲未知參數失敗。在這些系統上,無論如何都需要動態加載'IsWow64Process()'來檢測WOW64是否存在。 – 2014-05-22 15:46:47

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的好點,我應該適當地修改上面的代碼。

+0

在調用'ReadString()'之前,您不需要檢查'ValueExists()'。如果該值不存在,它將返回一個空字符串,但不會像其他閱讀方法那樣引發異常。 – 2014-05-22 15:49:12

相關問題