Delphi 从注册表读取会阻止COM服务器启动吗?
我有一些基本上调用CreateComObject的代码。。。检查注册表项HKEY\U CURRENT\U USER\SOFTWARE\Classes\CLSID\…\LocalServer32后,该项有效 问题是:COM服务器只有在我没有检查注册表项时才能正确加载 这怎么可能Delphi 从注册表读取会阻止COM服务器启动吗?,delphi,com,registry,Delphi,Com,Registry,我有一些基本上调用CreateComObject的代码。。。检查注册表项HKEY\U CURRENT\U USER\SOFTWARE\Classes\CLSID\…\LocalServer32后,该项有效 问题是:COM服务器只有在我没有检查注册表项时才能正确加载 这怎么可能 const csLibGuid : TGUID = '...'; csLibMd5Sum : string = '...'; csLibRegKey
const
csLibGuid : TGUID = '...';
csLibMd5Sum : string = '...';
csLibRegKeyFormatRegular : string = '\SOFTWARE\Classes\CLSID\%s\LocalServer32';
csLibRegKeyFormatWow64 : string = '\SOFTWARE\Classes\Wow6432Node\CLSID\%s\LocalServer32';
csLibClassName : string = '...';
procedure TLibLoader.CheckLibraryChecksum;
var
FileNames : TStringList;
Registry : TRegistry;
procedure AddFileName(AHKEY: HKEY; const AFormat: string);
begin
Registry.RootKey := AHKEY;
Registry.OpenKey(
Format(AFormat, [GUIDToString(csLibGuid)])
, False
);
try
FileName := Registry.ReadString(csEmpty);
if Trim(FileName) > csEmpty then begin
FileNames.Add(FileName);
end;
finally
Registry.CloseKey;
end;
end;
var
FileName : string;
FileDigest : string;
begin
Registry := TRegistry.Create(KEY_EXECUTE);
try
FileNames := TStringList.Create;
try
FileNames.Duplicates := dupIgnore;
FileNames.Sorted := True;
AddFileName(HKEY_LOCAL_MACHINE, csLibRegKeyFormatRegular);
AddFileName(HKEY_LOCAL_MACHINE, csLibRegKeyFormatWoW64);
AddFileName(HKEY_CURRENT_USER , csLibRegKeyFormatRegular);
AddFileName(HKEY_CURRENT_USER , csLibRegKeyFormatWoW64);
if FileNames.Count = 0 then begin
raise EProtector.Create('All registry keys are empty');
end;
for FileName in FileNames do begin
if not FileExists(FileName) then begin
raise Exception.Create(Format('File "%s" does not exist', [FileName]));
end;
FileDigest := TMD5.HashFile(FileName);
if not AnsiSameText(FileDigest, csLibMd5Sum) then begin
raise Exception.Create(Format('File "%s" is not valid', [FileName]));
end;
end;
finally
FileNames.Free;
end;
finally
Registry.Free;
end;
end;
CheckLibraryChecksum;
CreateComObject(csLibGuid);
您没有检查OpenKey的返回值。您必须这样做,并且只有在OpenKey返回True时才继续读取值 我怀疑其中一些钥匙不存在。然后忽略OpenKey返回的False,并尝试读取一个值。这将导致提出例外情况 所以你的函数应该是这样的:
procedure AddFileName(AHKEY: HKEY; const AFormat: string);
begin
Registry.RootKey := AHKEY;
if Registry.OpenKey(
Format(AFormat, [GUIDToString(csLibGuid)])
, False
) then begin
try
FileName := Registry.ReadString(csEmpty);
if Trim(FileName) > csEmpty then begin
FileNames.Add(FileName);
end;
finally
Registry.CloseKey;
end;
end;
end;
就我个人而言,我会使用OpenKeyReadOnly,因为我觉得它更明确。我意识到您正在使用KEY_EXECUTE作为访问值,这与KEY_READ相同。我只是觉得OpenKeyReadOnly使人类读者更容易验证意图。您没有检查OpenKey的返回值。您必须这样做,并且只有在OpenKey返回True时才继续读取值 我怀疑其中一些钥匙不存在。然后忽略OpenKey返回的False,并尝试读取一个值。这将导致提出例外情况 所以你的函数应该是这样的:
procedure AddFileName(AHKEY: HKEY; const AFormat: string);
begin
Registry.RootKey := AHKEY;
if Registry.OpenKey(
Format(AFormat, [GUIDToString(csLibGuid)])
, False
) then begin
try
FileName := Registry.ReadString(csEmpty);
if Trim(FileName) > csEmpty then begin
FileNames.Add(FileName);
end;
finally
Registry.CloseKey;
end;
end;
end;
就我个人而言,我会使用OpenKeyReadOnly,因为我觉得它更明确。我意识到您正在使用KEY_EXECUTE作为访问值,这与KEY_READ相同。我只是觉得OpenKeyReadOnly让人类读者更容易验证意图。顺便说一句,我不喜欢你的字符串比较。您使用TrimFileName>csEmpty,我发现这相当不透明。我希望csEmpty与相同。你应该在这里使用比较。我同意它给出了完全相同的结果,但是您对排序不感兴趣,您感兴趣的是文件名是否为空。我还建议您使用某种形式的日志记录来查明导致COM服务器故障的确切原因。这将在未来支付股息。@DavidHeffernan csEmpty是公司的政策,以避免与“”混淆。遗憾的是,我没有COM服务器的源代码,这使得调试更加困难。@DavidHeffernan:whaa。这已经有多久了,我错过了吗?@marjannema永远都在。不是我用的。我更喜欢。真正的问题是完全不同的:子过程AddFileName中没有FileName变量,因此代码设置了一个名为FileName的LibLoader类的属性,这会导致一些有害的副作用……顺便说一句,我对字符串比较不感兴趣。您使用TrimFileName>csEmpty,我发现这相当不透明。我希望csEmpty与相同。你应该在这里使用比较。我同意它给出了完全相同的结果,但是您对排序不感兴趣,您感兴趣的是文件名是否为空。我还建议您使用某种形式的日志记录来查明导致COM服务器故障的确切原因。这将在未来支付股息。@DavidHeffernan csEmpty是公司的政策,以避免与“”混淆。遗憾的是,我没有COM服务器的源代码,这使得调试更加困难。@DavidHeffernan:whaa。这已经有多久了,我错过了吗?@marjannema永远都在。不是我用的。我更喜欢。真正的问题是完全不同的:在子过程AddFileName中没有FileName变量,因此代码正在设置一个名为FileName的“LibLoader”类的属性,这会导致一些有害的副作用…感谢这两个建议,我将相应地更改代码。我想我必须想出一个更好的测试项目来更好地理解我的问题。也许我会就此问题写一个后续问题。顺便说一句:有趣的是,KEY_READ和KEY_EXECUTE实际上是相同的值,但在文档中有不同的描述:MSDN说的“KEY_EXECUTE”:相当于KEY_READ。我猜同步不再适用于注册表项。也许这是很久以前的事了。当您只读取密钥时,使用OpenKeyReadOnly而不是OpenKey也很重要,因为OpenKeyReadOnly会在内部尝试多种权限组合,直到在应用程序以标准用户和管理员的身份运行时,找到一种成功的权限组合,然后将TRegistry.Access属性设置为实际有效的值。OpenKey只使用当前的TRegistry.Access属性值,因此您必须事先确保它设置正确。感谢这两个建议,我将相应地更改代码。我想我必须想出一个更好的测试项目来更好地理解我的问题。也许我会写一个关于这个问题的后续问题。顺便说一句:有趣的是,KEY_READ和KEY_EXECUTE实际上是相同的值,但在文档中有不同的描述: MSDN称之为“KEY_EXECUTE”:相当于KEY_READ。我猜同步不再适用于注册表项。也许这是很久以前的事了。当您只读取密钥时,使用OpenKeyReadOnly而不是OpenKey也很重要,因为OpenKeyReadOnly会在内部尝试多种权限组合,直到在应用程序以标准用户和管理员的身份运行时,找到一种成功的权限组合,然后将TRegistry.Access属性设置为实际有效的值。OpenKey只使用当前的TRegistry.Access属性值,因此您必须事先确保它设置正确。