如何在InstallScript代码中添加倒计时计时器?兼询服务器响应检测方案
解决InstallScript CopyFile下载超时与服务器预检测问题
嘿,针对你遇到的服务器无响应时对话框卡住的问题,我给你两个可行的解决方案:一个是给下载操作加上超时限制,另一个是预先检测服务器是否可达,避免无效的下载尝试。
一、给下载添加超时计时器
InstallScript自带的CopyFile函数没有内置超时参数,咱们可以通过创建独立线程执行下载,再用等待函数设置超时时间的方式来实现超时控制。这样即使服务器无响应,到了设定时间就会终止下载并关闭提示对话框。
以下是修改后的代码示例:
// 声明线程函数原型 prototype DWORD DownloadThreadFunc(LPVOID); function OnInstall() STRING szEULAFile; HWND hWnd; DWORD dwThreadId; HANDLE hThread; DWORD dwWaitResult; CONST DWORD DOWNLOAD_TIMEOUT = 30000; // 设置30秒超时(单位:毫秒) // 初始化szEULAFile为本地保存路径,比如: szEULAFile = TARGETDIR ^ "sample.rtf"; SdShowMsg("Please Wait... Downloading file from our server...", TRUE); // 创建线程执行下载操作 hThread = CreateThread(NULL, 0, DownloadThreadFunc, &szEULAFile, 0, &dwThreadId); if (hThread != NULL) then // 等待线程完成,或超时 dwWaitResult = WaitForSingleObject(hThread, DOWNLOAD_TIMEOUT); switch(dwWaitResult) case WAIT_OBJECT_0: // 下载成功完成 MessageBox("Download completed successfully!", INFORMATION); case WAIT_TIMEOUT: // 超时,终止线程 TerminateThread(hThread, 1); MessageBox("Download timed out. Server may be unavailable.", WARNING); default: // 等待出错 MessageBox("Error occurred during download.", SEVERE); endswitch; CloseHandle(hThread); else MessageBox("Failed to start download thread.", SEVERE); endif; SdShowMsg("Please Wait... Downloading file from our server...", FALSE); end; // 线程函数:执行下载 function DWORD DownloadThreadFunc(LPVOID lpParam) STRING* pszDestFile = lpParam; STRING szSourceURL = "https://<downloadURL>/sample.rtf"; // 执行下载 if (CopyFile(szSourceURL, *pszDestFile) != 0) then return 0; // 成功返回0 else return 1; // 失败返回1 endif; end;
二、预先检测服务器是否响应
在执行下载前,咱们可以先用WinINet API发送一个HEAD请求来检测服务器是否可达,这样能提前判断下载能否进行,避免后续卡住。
以下是预检测的代码示例:
// 声明WinINet相关函数原型 prototype BOOL InternetOpenA(STRING,DWORD,STRING,STRING,DWORD); prototype BOOL InternetConnectA(HANDLE,STRING,INTEGER,STRING,STRING,DWORD,DWORD,DWORD); prototype BOOL HttpOpenRequestA(HANDLE,STRING,STRING,STRING,STRING,STRING*,DWORD,DWORD); prototype BOOL HttpSendRequestA(HANDLE,STRING,DWORD,STRING,DWORD); prototype BOOL InternetCloseHandle(HANDLE); prototype BOOL HttpQueryInfoA(HANDLE,DWORD,STRING*,DWORD*,DWORD*); function BOOL IsServerReachable(STRING szServerURL) HANDLE hInternet, hConnect, hRequest; STRING szServer, szPath; INTEGER nPort; STRING szStatusCode; DWORD dwStatusCodeLen = 10; BOOL bResult = FALSE; // 解析URL,分离服务器地址和路径(这里需要你根据实际URL调整,或者用URL解析函数) // 示例:假设szServerURL是"https://<downloadURL>/sample.rtf" szServer = "<downloadURL>"; szPath = "/sample.rtf"; nPort = 443; // HTTPS默认端口 // 初始化WinINet hInternet = InternetOpenA("InstallScript Download Check", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hInternet != NULL) then // 连接服务器 hConnect = InternetConnectA(hInternet, szServer, nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); if (hConnect != NULL) then // 创建HEAD请求 hRequest = HttpOpenRequestA(hConnect, "HEAD", szPath, NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0); if (hRequest != NULL) then // 发送请求 if (HttpSendRequestA(hRequest, NULL, 0, NULL, 0)) then // 获取响应状态码 if (HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE, szStatusCode, &dwStatusCodeLen, NULL)) then // 状态码200表示服务器正常响应 if (szStatusCode == "200") then bResult = TRUE; endif; endif; endif; InternetCloseHandle(hRequest); endif; InternetCloseHandle(hConnect); endif; InternetCloseHandle(hInternet); endif; return bResult; end; // 在主流程中调用预检测 function OnInstall() STRING szEULAFile; STRING szDownloadURL = "https://<downloadURL>/sample.rtf"; szEULAFile = TARGETDIR ^ "sample.rtf"; // 先检测服务器是否可达 if (IsServerReachable(szDownloadURL)) then SdShowMsg("Please Wait... Downloading file from our server...", TRUE); if (CopyFile(szDownloadURL, szEULAFile) != 0) then MessageBox("Download completed!", INFORMATION); else MessageBox("Download failed even though server was reachable.", WARNING); endif; SdShowMsg("Please Wait... Downloading file from our server...", FALSE); else MessageBox("Server is unavailable. Cannot download file.", WARNING); endif; end;
注意事项
- 线程方案中,
TerminateThread是强制终止线程的方式,虽然简单但可能存在资源泄漏风险,如果需要更优雅的终止,可以在线程中定期检查一个全局标志位,超时后设置标志位让线程自行退出。 - WinINet方案需要确保你的InstallScript工程已经链接了
wininet.lib,并且注意URL解析的准确性(如果URL有复杂路径,建议用InternetCrackUrl函数来解析)。
内容的提问来源于stack exchange,提问作者Ajit Medhekar
相关产品推荐
相关产品推荐

