Thema: Delphi Registry: WOW6432NODE

Einzelnen Beitrag anzeigen

Benutzerbild von Rakshasa
Rakshasa

Registriert seit: 1. Nov 2003
182 Beiträge
 
Delphi 2007 Professional
 
#1

Registry: WOW6432NODE

  Alt 16. Feb 2007, 22:16
Problem: Unter einem 64-Bit-Windows (bspw. XP oder Vista) werden Anfragen von 32-Bit und 64-Bit Programmen unterschiedlich beantwortet: MSDN

Beispiel:
Unsere (32-Bit) Anwendung möchte auf den Schlüssel "HKEY_LM\Software\Microsoft\Windows" zugreifen (Schreibzugriff).
Tatsächlich aber wird die Anfrage von TRegistry umgeleitet, auf den Schlüssel "HKEY_LM\Software\WOW6432Node\Microsoft\Window s". D.h., der Wert wird in den Schlüssel "HKEY_LM\Software\WOW6432Node\Microsoft\Window s" geschrieben, statt in "KEY_LM\Software\Microsoft\Windows ".

Lösung:
Die TRegistry muss mit speziellen Zugriffsrechten geöffnet werden, um 32-Bit-Anwendungen expliziten Zugriff auf einen der beiden Schlüssel zu geben (also 32-Bit: "HKEY_LM\Software\WOW6432Node\..." oder 64-Bit: "HKEY_LM\Software\...").
Wichtig: Meine Lösungen gehen davon, dass das Programm über Abwärtskompatibilität verfügen soll, d.h. je nachdem, ob ein 64-Bit oder 32-Bit Windows entdeckt wurde, wird anders verfahren.
Um herauszufinden, ob Windows 64-Bit installiert wurde, kann folgende Funktion (von hier) verwendet werden:

Delphi-Quellcode:
function IsWow64: Boolean;
type
  TIsWow64Process = function( // Type of IsWow64Process API fn
    Handle: Windows.THandle; var Res: Windows.BOOL
  ): Windows.BOOL; stdcall;
var
  IsWow64Result: Windows.BOOL; // Result from IsWow64Process
  IsWow64Process: TIsWow64Process; // IsWow64Process fn reference
begin
  // Try to load required function from kernel32
  IsWow64Process := Windows.GetProcAddress(
    Windows.GetModuleHandle('kernel32'), 'IsWow64Process'
  );
  if Assigned(IsWow64Process) then
  begin
    // Function is implemented: call it
    if not IsWow64Process(
      Windows.GetCurrentProcess, IsWow64Result
    ) then
      raise SysUtils.Exception.Create('IsWow64: bad process handle');
    // Return result of function
    Result := IsWow64Result;
  end
  else
    // Function not implemented: can't be running on Wow64
    Result := False;
end;
So, um jetzt ordentlich zugreifen zu können, müssen zwei neue Typen deklariert werden (MSDN):
Delphi-Quellcode:
 const
 KEY_WOW64_64KEY = $0100;
 KEY_WOW64_32KEY = $0200;
Beispielcode für den LESE-Zugriff (32-Bit-Anwendung) auf einen Unterschlüssel von "HK_LM\Software\...":

Delphi-Quellcode:
var
  s1,s2: String;
begin

  // Auf Schlüssel "HKEY_LM\Software\WOW6432Node\Microsoft\Windows" zugreifen (umgeleitet!)
  with TRegistry.Create do
  begin
    try
      RootKey := HKEY_LOCAL_MACHINE;
      if OpenKey('\Software\Microsoft\Windows', false) then
      begin
        s1 := ReadString('');
        CloseKey;
      end;
    finally
      free;
    end;
  end;

  // Und jetzt auf den Schlüssel "HKEY_LM\Software\Microsoft\Windows" zugreifen
  with TRegistry.Create(KEY_ALL_ACCESS OR KEY_WOW64_64KEY) do
  begin
    try
      RootKey := HKEY_LOCAL_MACHINE;
      if OpenKey('\Software\Microsoft\Windows', false) then
      begin
        s2 := ReadString('');
        CloseKey;
      end;
    finally
      free;
    end;
  end;

  Showmessage(s1 + #13 + s2);
end;
Der Schreibzugriff ist jetzt ein wenig aufwendiger, ich habe mir dazu eine kleine Function gebaut, die immer - je nach Bedarf - in den einen oder anderen Schlüssel schreibt. Läuft die Anwendung auf einem 32-Bit-Windows, wird der Standard-AccessMode zurückgegeben.
Dabei wird wird an die Function der zu schreibende Schlüsselname gegeben, also bspw. "HKEY_LM\Software\WOW6432Node\Microsoft\Window s" oder "HKEY_LM\Software\Microsoft\Windows". Der Witz ist jetzt, dass durch die Function tatsächlich auch in den angegebenen Schlüssel geschrieben wird, es erfolgt keine "Umleitung".

Achtung: Beispiel verwendet Smartpos() der Unit FastStrings, da SmartPos() nicht case-sensitive ist. Das Beispiel kann natürlich auch mit Pos() benutzt werden.

Delphi-Quellcode:
function GetRegAccessMode(sOrtID: String): Cardinal;
begin
  // Bei 32-Bit-Windows kein spezieller Accessmode erforderlich
  if not Is64BitWindows then begin
    Result := KEY_ALL_ACCESS;
    exit;
  end;

  if SmartPos('Wow6432Node', sOrtID, false) > 0 then // 32-Bit-Wert schreiben?
    result := (KEY_ALL_ACCESS OR KEY_WOW64_32KEY)
  else
    result := (KEY_ALL_ACCESS OR KEY_WOW64_64KEY);

  // Alternativ: Mit pos() -> case-sensitive!
  {
  if Pos('Wow6432Node', sOrtID) > 0 then // 32-Bit-Wert schreiben?
    result := (KEY_ALL_ACCESS OR KEY_WOW64_32KEY)
  else
    result := (KEY_ALL_ACCESS OR KEY_WOW64_64KEY);
  }

end;
Eingebaut wird dass dann in den .Create-Aufruf von TRegistry:

Delphi-Quellcode:
var
  AccessMode: Cardinal;
  sKey: String;
begin
  sKey := '\Software\Microsoft\Windows';
  AccessMode := GetRegAccessMode(sKey);

  with TRegistry.Create(AccessMode) do
  begin
    try
      {.........}
    finally
      free;
    end;
 end;
Fertig!!

[edit=CalganX]Code-Style und Ressourcenschutz. Mfg, CalganX[/edit]
  Mit Zitat antworten Zitat