Вопрос, с которым сталкиваются разработчики, работающие с WinHTTP в среде Delphi, заключается в том, как сохранить поток ответа IWinHttpRequest.ResponseStream на диск. При использовании Type Library импорта WinHTTP в Delphi, разработчики сталкиваются с трудностями при работе с OLE-вариантами, которые не позволяют напрямую копировать поток в файл.
Описание проблемы
При попытке использовать WinHTTP для загрузки файла, разработчики успешно выполняют запрос, но сталкиваются с проблемой сохранения ответа в виде потока. OLE-вариант, возвращаемый свойством ResponseStream интерфейса IWinHttpRequest, не может быть напрямую использован для копирования в файловый поток.
Контекст
В приведенном коде функции Download используется OLE-вариант для работы с ResponseStream, но возникает ошибка выполнения, связанная с OLE-вариантами (EOleError 'Variant does not reference an automation object') при попытке копирования потока в файл.
// ... код функции Download ...
var
http: IWinHttpRequest;
fs: TFileStream;
FileStream: IStream;
sz, rd, wr: Int64;
begin
// ... код инициализации и выполнения запроса ...
if result then
begin
fs := TFileStream.Create(filename, fmCreate, fmShareExclusive);
try
FileStream := TStreamAdapter.Create(fs, soReference) as IStream;
sz := http.ResponseStream.Size;
http.ResponseStream.CopyTo(FileStream, sz, rd, wr);
finally
FileStream := nil;
fs.Free;
end;
end;
end;
Подтвержденный ответ
Для решения проблемы необходимо использовать класс AxCtrls.TOleStream, который позволяет общаться между потоком ответа IWinHttpRequest.ResponseStream и Classes.TFileStream. Пример использования TOleStream в коде:
{$APPTYPE CONSOLE}
uses
Variants,
ActiveX,
Classes,
AxCtrls,
WinHttp_TLB,
SysUtils;
function Download(const url, filename: String): Boolean;
var
http: IWinHttpRequest;
wUrl: WideString;
fs: TFileStream;
HttpStream: IStream;
sz, rd, wr: Int64;
FStatus: Integer;
OleStream: TOleStream;
begin
try
wUrl := url;
http := CoWinHttpRequest.Create;
http.open('GET', wUrl, False);
http.send(EmptyParam);
FStatus := http.status;
result := FStatus = 200;
if result then
begin
HttpStream := IUnknown(http.ResponseStream) as IStream;
OleStream := TOleStream.Create(HttpStream);
try
fs := TFileStream.Create(filename, fmCreate);
try
OleStream.Position := 0;
fs.CopyFrom(OleStream, OleStream.Size);
finally
fs.Free;
end;
finally
OleStream.Free;
end;
end;
except
result := false;
// Обработка исключений
end;
end;
begin
try
Download('http://foo.html', 'C:\Foo\anyfile.foo');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Альтернативный ответ
В качестве альтернативного подхода можно было бы рассмотреть другие способы работы с OLE-вариантами, однако, использование AxCtrls.TOleStream является проверенным и рекомендуемым решением для данной задачи.
Заключение
При работе с OLE-вариантами в Delphi важно правильно их обрабатывать, чтобы избежать ошибок, связанных с некорректным взаимодействием между интерфейсами COM и VCL. Использование TOleStream позволяет корректно копировать поток ответа WinHTTP в файл, что является ключом к решению описанной проблемы.
Проблема заключается в том, как правильно использовать OLE-варианты в Delphi для сохранения ответа от WinHTTP запроса в файл, что требует применения специального класса для работы с потоками.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.