IStorage не разблокируется после фиксации

Когда я запускаю приведенную ниже программу, результирующее значение stgOpenStorage равно STG_E_SHAREVIOLATION. Как мне закрыть IStorage, чтобы разблокировать его?

      procedure TForm1.btnSaveClick(Sender: TObject);
var
  fileName : string;
  streamName : string;

  procedure storeTextIntoStorageStream( text_ : string );
  var
    documentStorage : IStorage;
    levelIStream : IStream;
    i, j : integer;
  begin
    if ( fileExists( fileName ) ) then
      deleteFile( fileName );
    stgCreateDocfile( @fileName[1], STGM_WRITE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT or STGM_CREATE, 0, documentStorage );
    try
      documentStorage.CreateStream( @streamName[1], STGM_WRITE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT, 0, 0, levelIStream );
      try
        i := length( text_ );
        levelIStream.write( @i, sizeOf( integer ), @j );
        levelIStream.write( @text_[1], i*sizeOf( char ), @j );
      finally
        levelIStream.Commit( 0 );
        levelIStream := NIL;
      end;
    finally
      documentStorage.Commit( 0 );
      documentStorage := NIL;
    end;
  end;

  function readTextFromStorageStream : string;
  var
    documentStorage : IStorage;
    levelIStream : IStream;
    i, j : integer;
  begin
    i := stgOpenStorage( @fileName[1], NIL, STGM_READ or STGM_SHARE_EXCLUSIVE or STGM_DIRECT, NIL, 0, documentStorage );
    try
      documentStorage.OpenStream( @streamName[1], NIL, STGM_READ or STGM_SHARE_EXCLUSIVE or STGM_DIRECT, 0, levelIStream );
      try
        levelIStream.read( @i, sizeOf( integer ), @j );
        setLength( result, i );
        levelIStream.read( @result[1], i*sizeOf( char ), @j );
      finally
        levelIStream := NIL;
      end;
    finally
      documentStorage := NIL;
    end;
  end;

begin
  fileName := 'c:\temp\test.stg';
  streamName := 'Stream-0';
  storeTextIntoStorageStream( memo1.Lines.DelimitedText );
  memo1.Lines.DelimitedText := readTextFromStorageStream;
end;

И как я могу установить шаг размера/размера IStorage/IStream по умолчанию? Поскольку мой тестовый контент размером 1,6 КБ хранится в 16 КБ.

2 ответа

В исходных библиотеках Delphi есть две реализации IStorage. и . Какой из них вы используете? вWinApi.OLE2unit, IStorage и IStream — это КЛАССЫ, а не ИНТЕРФЕЙСЫ. Если вы используете этот модуль, сборка мусора интерфейса и поэтому автоматическое закрытие переменных не работает. Если вы используетеWinApi.ActiveXединица, пример будет работать просто отлично.

Код выглядит нормально 1 , поэтому у меня есть ощущение, что проблема связана с тем, что вы используете . Файл используется в то время, когда вы пытаетесь его открыть, поэтому я держу пари, что ваша ОС / AV держит файл открытым (т. Е. Для сканирования его содержимого), а не интерфейсы вstoreTextIntoStorageStream(), которые уже давно ушли к моменту ввода.

1: ну, кроме отсутствия адекватной обработки ошибок. И лишнее nil'ing интерфейсных переменных. И рассмотрите возможность замены ваших строковых индексов на PChar()вместо этого бросает.

ВreadTextFromStorageStream(), попробуйте заменитьSTGM_SHARE_EXCLUSIVE(что имеет смысл для писателя, но не для читателя) сSTGM_SHARE_DENY_WRITEвместо этого и посмотрите, исчезнет ли ошибка:

      procedure TForm1.btnSaveClick(Sender: TObject);
var
  fileName : string;
  streamName : string;

  procedure storeTextIntoStorageStream( const text_ : string );
  var
    documentStorage : IStorage;
    levelIStream : IStream;
    i, j : integer;
  begin
    if ( FileExists( fileName ) ) then
      DeleteFile( fileName );
    OleCheck( StgCreateDocFile( PChar(fileName), STGM_WRITE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT or STGM_CREATE, 0, documentStorage ));
    try
      OleCheck( documentStorage.CreateStream( PChar(streamName), STGM_WRITE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT, 0, 0, levelIStream ) );
      try
        i := Length( text_ );
        OleCheck( levelIStream.Write( @i, SizeOf( i ), @j ) );
        if ( i > 0 ) then
          OleCheck( levelIStream.Write( PChar(text_), i * SizeOf( Char ), @j ) );
      finally
        levelIStream.Commit( 0 );
      end;
    finally
      documentStorage.Commit( 0 );
    end;
  end;

  function readTextFromStorageStream : string;
  var
    documentStorage : IStorage;
    levelIStream : IStream;
    i, j : integer;
  begin
    Result := '';
    OleCheck( StgOpenStorage( PChar(fileName), nil, STGM_READ or STGM_SHARE_DENY_WRITE or STGM_DIRECT, NIL, 0, documentStorage ) );
    OleCheck( documentStorage.OpenStream( PChar(streamName), nil, STGM_READ or STGM_SHARE_DENY_WRITE or STGM_DIRECT, 0, levelIStream ) );
    OleCheck( levelIStream.Read( @i, SizeOf( i ), @j ) );
    if ( i > 0 ) then
    begin
      SetLength( Result, i );
      OleCheck( levelIStream.Read( PChar(Result), i * SizeOf( Char ), @j ) );
    end;
  end;

begin
  fileName := 'c:\temp\test.stg';
  streamName := 'Stream-0';
  storeTextIntoStorageStream( Memo1.Lines.DelimitedText );
  Memo1.Lines.DelimitedText := readTextFromStorageStream;
end;
Другие вопросы по тегам