2

我有一些代码CreateComObject(...)在检查注册表项HKEY_CURRENT_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);
4

1 回答 1

4

您没有检查OpenKey. 您必须这样做,并且只有在OpenKey返回时才继续读取值True

我怀疑其中一些键不存在。然后,您忽略False返回OpenKey的值并尝试读取一个值。这将导致引发异常。

所以你的功能应该是这样的:

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_EXECUTEAccess价值与KEY_READ. 我只是觉得这OpenKeyReadOnly让人类读者更容易验证意图。

于 2013-02-07T17:00:26.243 回答