使用wininet下载文件时如何避免冻结
Posted
技术标签:
【中文标题】使用wininet下载文件时如何避免冻结【英文标题】:how to avoid freezing when download file using wininet 【发布时间】:2015-05-09 13:38:40 【问题描述】:我使用wininet下载图像并将其保存到内存流这是我的程序
procedure DownloadToStream(const Url: string; ms: TMemoryStream);
var
hSession : HINTERNET;
hService : HINTERNET;
lpBuffer : array[0..1023] of Byte;
dwBytesRead : DWORD;
dwBytesAvail : DWORD;
dwTimeOut : DWORD;
begin
hSession := InternetOpen('usersession', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if not Assigned(hSession) then Exit;
try
hService := InternetOpenUrl(hSession, PChar(Url), nil, 0, 0, 0);
if hService = nil then
Exit;
try
dwTimeOut := 60000;
InternetSetOption(hService, INTERNET_OPTION_RECEIVE_TIMEOUT, @dwTimeOut, SizeOf(dwTimeOut));
if InternetQueryDataAvailable(hService, dwBytesAvail, 0, 0) then
repeat
if not InternetReadFile(hService, @lpBuffer[0], SizeOf(lpBuffer), dwBytesRead) then
Break;
if dwBytesRead <> 0 then
ms.WriteBuffer(lpBuffer[0], dwBytesRead);
until dwBytesRead = 0;
finally
InternetCloseHandle(hService);
end;
finally
InternetCloseHandle(hSession);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ms: TMemoryStream;
begin
ms := TMemoryStream.Create;
try
DownloadToStream('imageurl, ms);
ms.Position := 0;
//do whatever you want with ms
finally
ms.Free;
end;
end;
在下载小图像时它工作正常并且没有冻结,但是当它涉及到大图像时,应用程序在下载完成之前一直冻结,如何避免这种情况?
【问题讨论】:
您应该花一点时间了解 Windows 消息循环的工作原理,并观察您的函数是从消息循环中调用的。 如果您想阅读有关 windows 消息循环的好文章,这是一篇很棒的文章:edn.embarcadero.com/article/38447 非常感谢您的指导,我在重复直到处理冻结之间使用了Application.ProcessMessages;
@DelphiStudent Now... 请注意:delphi.about.com/od/objectpascalide/a/… ProcessMessages
是一个快速而肮脏的修复,但它是肮脏的编程,如果你正在构建除混搭测试应用程序之外的任何东西最终会回来咬你。
是的,你是对的,我可能会将代码从 DownloadToStream 移动到线程 OnExecute 事件
【参考方案1】:
您的程序正在冻结,因为在下载完成之前调用不会返回,而且正如您从网页浏览中知道的那样,有时这可能需要很长时间。发生这种情况时,您的程序没有运行正常的事件循环和处理输入。
如果您想让它正常工作,您需要在不同的线程中进行下载。多线程可能非常棘手,但使用正确的库会变得简单得多。对于这样的事情,我建议查看the Async/Await functionality in OmniThreadLibrary.
【讨论】:
谢谢你的回答,如果我用idhttp
会容易得多?
@DelphiStudent:不是这样。 TIdHTTP
仍然同步下载东西。如果要保持 UI 响应,则需要异步执行长时间运行的任务。 OmniThreadLibrary 确实可以帮助您做到这一点。
Indy 不是也支持多线程,也就是说它的代码可以在额外的线程中执行吗?我知道 TIdTCPServer 支持处理接收到的命令,但我不确定其他 Indy 组件。以上是关于使用wininet下载文件时如何避免冻结的主要内容,如果未能解决你的问题,请参考以下文章