2012-02-02 8 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を使用しないのですか?あなたのロジックも本当に混乱しています。関数を呼び出して値を読み取る必要があります。それを2回呼ぶ。最初のパス0。2回目のパスはKEY_WOW64_64KEYです。最初の時間が失敗した場合にのみ、2回目を呼び出します。これは、メソッドのリファクタリングを抽出します。 –

+0

以前はTRegistryを使っていましたが、KEY_WOW64_64KEYをコンストラクタを介してパラメータで追加することはできませんでした。 –

+1

確かにそうです。私の答えを見てください。編集:今私の答えを見つけたように見えます。また、 'Access'プロパティはいつでも変更でき、既に作成されたレジストリオブジェクト内のビューを切り替えることができます。 –

答えて

6

あなたのコードは、低レベルのレジストリAPIのすべての複雑さからあなたを守る組み込みのTRegistryクラスを利用していないため、複雑ではありません。

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; 

機能ReadRegStrRootルート鍵の鍵Key相対からNameという名前の文字列値を返します。たとえば、次のコードを検討してください。エラーがある場合、たとえばキーまたは名前が存在しない場合、または値のタイプが間違っている場合は、例外が発生します。

Viewパラメータは、レジストリの32ビットまたは64ビットのネイティブ・ビューに簡単にアクセスできる列挙型です。ネイティブは、実行中のプロセスにネイティブであることに注意してください。したがって、32ビットプロセスの場合は32ビットビュー、64ビットプロセスの場合は64ビットビューになります。この列挙は、.netの同等の定義を反映しています。

+0

nopeはまだ動作しません。ReadStringは空の文字列を返します(自分のノートパソコンに問題はありますか?):const KEY_WOW64_64KEY = $ 0100; var r:TRegistry; s:文字列。 begin r:= TRegistry.Create(KEY_READまたはKEY_WOW64_64KEY); r.RootKey:= HKEY_LOCAL_MACHINE; r.OpenKeyReadOnly( 'Software \ Microsoft \ Cryptography')then s:= r.ReadString( 'MachineGuid'); –

+0

私のコードにバグがあり、ただ修正しました。 RootKey。しかし、あなたはすでにそれを持っています。あなたのコードはうまくいくはずです。そこに鍵があるの? 1時間ほどで私のマシンをチェックします。ディナータイムはここ! –

+0

私はコードをテストしました。値が存在しないときに 'TRegistry'がどのように動作するのか、私は理解していなかったので、修正したバグがありました。しかし、あなたが空の文字列を見ているなら、何かが間違っています。あなたのコード(と私のコード)は、私がそれらを実行するときに正しい値を返します。私はどのバージョンのDelphiを使用しているのだろうか。おそらくあなたは 'TRegistry'が' KEY_WOW64_64KEY'を尊重しない古いDelphi上にいるでしょう。それは私を驚かせるだろう。私はあなたが 'KEY_WOW64_64KEY'を定義しているのでこれを少し疑っていますが、Windows.pasから取得しています。だから、あなたは何を使っていますか? –

10

私はあなたが64ビットOS上で実行されている32-プロセスのときに知っておくIsWow64Process()機能を使うことをお勧めして、その特定の条件でKEY_WOW64_64KEYフラグを適用します。アプリケーションが32ビットOS上の32ビットプロセス、または64ビットOS上の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 os – Remko

+1

で無視されます。無条件で 'KEY_WOW64_64KEY'を使用することができます –

+2

32ビット版でも、64ビットシステムの存在を認識するXP以降でのみ有効です。 Win2k以前のバージョンでフラグを指定すると、未知のパラメータとして失敗します。これらのシステムでは、WOW64が存在するかどうかを検出するために、IsWow64Process()を動的にロードする必要があります。 –

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()'をチェックする必要はありません。値が存在しない場合は空の文字列を返し、他の読み取りメソッドと同様に例外は発生しません。 –

関連する問題