我一直使用来自HKEY_LOCAL_MACHINE\Software\Microsoft\Cryptography
的关键MachineGuid
的值来唯一标识主机,但是在64位计算机上运行的32位进程中,该值似乎丢失。 我想这是在Wow6432Node,它确实缺less的地方search。 根据这个,你应该能够通过添加一个标志来正确的键,但是下面的代码仍然不能完成这项工作。 我错过了什么?
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;
你的代码是非常复杂的,很大程度上是因为你没有利用内置的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中的等效定义。
我建议您使用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;
在我使用这个注册表键我更进一步。 如果值不存在,我创建它:不在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的一个好点, 我应该适当地修改上面的代码。