Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 从注册表读取会阻止COM服务器启动吗?_Delphi_Com_Registry - Fatal编程技术网

Delphi 从注册表读取会阻止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

我有一些基本上调用CreateComObject的代码。。。检查注册表项HKEY\U CURRENT\U USER\SOFTWARE\Classes\CLSID\…\LocalServer32后,该项有效

问题是:COM服务器只有在我没有检查注册表项时才能正确加载

这怎么可能

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属性值,因此您必须事先确保它设置正确。