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.OLE2
unit, 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;