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]