【发布时间】:2011-10-14 07:52:33
【问题描述】:
如何在 Inno 中从 Internet 下载文件。但请记住,我想要异步下载。换句话说,我希望下载从后台开始,并且 UI 会响应。
据我所知,似乎没有任何方法可以在 inno 脚本中进行异步下载,因为它不支持 theads 和 timer。
您能帮我解决这个问题吗?或者让我知道任何其他方式来实现这一目标?
【问题讨论】:
标签: dll inno-setup pascal
如何在 Inno 中从 Internet 下载文件。但请记住,我想要异步下载。换句话说,我希望下载从后台开始,并且 UI 会响应。
据我所知,似乎没有任何方法可以在 inno 脚本中进行异步下载,因为它不支持 theads 和 timer。
您能帮我解决这个问题吗?或者让我知道任何其他方式来实现这一目标?
【问题讨论】:
标签: dll inno-setup pascal
看看InnoTools Downloader。它正是为此目的而编写的,并提供了下载进度等。
【讨论】:
我不确定这是否可以做到。您也许可以编写一个具有两个功能的扩展 DLL:
一个为下载生成一个新线程(传递下载 URL 和一个临时文件名)和另一个您可以定期调用以检查下载是否完成或发生错误的线程。
然后,您将在安装开始时调用第一个函数(确保在卸载时不开始下载)。当您需要下载的文件时调用第二种方法。在某些时候,您需要等待下载完成。
另外,考虑一下,取消下载线程的另一个函数会很有用,因此您可以对取消的设置做出反应。
请参阅this question 以查找有关如何从 Pascal 脚本调用 DLL 中的函数的提示。
编辑
为了更清楚地说明我希望这些函数做什么,我正在尝试编写一些伪代码(可能看起来有点像 C# ;-)):
// This is a global variable for the thread
Thread globalDownloadThread = null;
bool threadFinished = false;
bool threadShouldFinish = false;
void StartDownload(string url, string outputFile)
{
globalDownloadThread = new Thread(DownloadThreadMethod);
globalDownloadThread.Start(url, outputFile);
}
void DownloadThreadMethod(string url, string outputFile)
{
bool downloadComplete = false;
bool downloadErrors = false;
while (!threadShouldFinish && !downloadComplete && !downloadErrors)
{
// Download a bit of the file
// Save to the output file
// Store errors
if (error)
downloadErrors = true;
else if (noMoreBytesToDownload)
// When we're done...
downloadComplete = true;
}
threadFinished = true;
}
void CancelThread()
{
threadShouldFinish = true;
globalDownloadThread.Join(); // Wait for thread to finish!
}
bool IsThreadDone()
{
return threadFinished;
}
在 Inno Setup 中,首先调用 StartDownload 方法。如果在调用StartDownload 后取消设置(只有这样才有线程!),请调用CancelThread。
在您需要确保文件已下载的地方,反复调用IsThreadDone,直到它返回true。
当然,这必须加上锁定机制,这里没有真正的错误报告,但我希望你能明白我的想法。
编辑 2
我会将您在 cmets 中发布的一些伪代码翻译成 C++。
HANDLE hThread = 0;
DWORD dwThreadId = 0;
DWORD dwThreadResult = 0;
extern "C" bool _declspec(dllexport) downloadfile(TCHAR *url, TCHAR *dest)
{
DOWNLOADPARAM *obj = new DOWNLOADPARAM();
obj->szURL = url;
obj->szFilePath = dest;
if ((hThread = CreateThread(NULL, 0, inetTransfer, (LPVOID)obj, 0,&dwThreadId)) == NULL)
{
return FALSE;
}
return TRUE;
}
extern "C" bool _declspec(dllexport) isThreadDone()
{
DWORD res = WaitForSingleObject(hThread, 10);
if (res == WAIT_OBJECT_0)
return TRUE;
// Set error flag depending on other values of res
dwThreadResult = res;
return FALSE;
}
extern "C" DWORD _declspec(dllexport) isThreadErrored()
{
return dwThreadResult;
}
while 函数中是否存在 while 循环并不重要 - 您很可能甚至需要某种循环! downloadfile 函数创建线程并返回。其他函数用于检查线程是否成功结束。
【讨论】:
WaitForSingleObject 的调用。删除它,您的实现也不会阻塞。我的实现将不阻塞,因为我不等待线程在InnoSetup 调用的函数中完成。 while 循环阻塞线程(这是需要的),但线程独立运行。再说一遍:StartDownload 函数启动线程并返回。 thread 方法在 while 循环中运行,直到所有内容都下载完毕,但在后台运行,不会阻塞 InnoSetup。
InnoTools 下载器好像很久没更新了,不支持 UNICODE...
还有一个看起来很有希望的项目:https://bitbucket.org/mitrich_k/inno-download-plugin 它于 2016 年 12 月更新,支持 ANSI 和 UNICODE 版本的 InnoSetup。 它有示例,文档还可以,它甚至支持多种语言,如西班牙语、中文...
【讨论】: