Ejemplo n.º 1
0
        // 从 Web 服务器安装或者升级绿色版
        // result.Value:
        //      -1  出错
        //      0   经过检查发现没有必要升级
        //      1   成功
        //      2   成功,但需要立即重新启动计算机才能让复制的文件生效
        public static async Task <NormalResult> InstallFromWeb(string downloadUrl,
                                                               string installDirectory,
                                                               string userDirectory,
                                                               // string waitExe,
                                                               bool delayUpdate,
                                                               Delegate_setProgress setProgress)
        {
            string strBaseUrl = downloadUrl;

            if (strBaseUrl[strBaseUrl.Length - 1] != '/')
            {
                strBaseUrl += "/";
            }

            string strBinDir = installDirectory;

            string strUtilDir = GetUtilDir(strBinDir);

            setProgress?.Invoke(0, 0, 0, "开始自动更新(绿色安装)");

            // 检查状态文件
            // result.Value
            //      -1  出错
            //      0   不存在状态文件
            //      1   正在下载 .zip 过程中。.zip 不完整
            //      2   当前 .zip 和 .exe 已经一样新
            //      3   当前 .zip 比 .exe 要新。需要展开 .zip 进行更新安装
            //      4   下载 .zip 失败。.zip 不完整
            //      5   当前 .zip 比 .exe 要新,需要重启计算机以便展开的文件生效
            var check_result = CheckStateFile(strBinDir);

            if (check_result.Value == -1)
            {
                return(check_result);
            }
            if (check_result.Value == 1 || check_result.Value == 3 || check_result.Value == 5)
            {
                return(new NormalResult());
            }

            // 希望下载的文件。纯文件名
            List <string> filenames = new List <string>()
            {
                // "greenutility.zip", // 这是工具软件,不算在 dp2circulation 范围内
                "app.zip",
                "data.zip"
            };

            // 发现更新了并下载的文件。纯文件名
            List <string> updated_filenames = new List <string>();

            // 需要确保最后被展开的文件。如果下载了而未展开,则下次下载的时候会发现文件已经是最新了,从而不会下载,也不会展开。这就有漏洞了
            // 那么就要在下载和展开这个全过程中断的时候,记住删除已经下载的文件。这样可以迫使下次一定要下载和展开
            List <string> temp_filepaths = new List <string>();

            try
            {
                int downloadCount = 0;
                foreach (string filename in filenames)
                {
                    string strUrl = // "http://dp2003.com/dp2circulation/v2/"
                                    strBaseUrl
                                    + filename;
                    string strLocalFileName = Path.Combine(strBinDir, filename).ToLower();

                    if (File.Exists(strLocalFileName) == true)
                    {
                        // this.DisplayBackgroundText("检查文件版本 " + strUrl + " ...\r\n");

                        // 判断 http 服务器上一个文件是否已经更新
                        // return:
                        //      -1  出错
                        //      0   没有更新
                        //      1   已经更新
                        var result = await IsServerFileUpdated(strUrl,
                                                               File.GetLastWriteTimeUtc(strLocalFileName));

                        if (result.Value == -1)
                        {
                            if (downloadCount > 0)
                            {
                                WriteStateFile(strBinDir, "downloadError");
                            }

                            return(result);
                        }
                        if (result.Value == 1)
                        {
                            updated_filenames.Add(filename);
                        }
#if NO
                        else
                        {
                            this.DisplayBackgroundText("没有更新。\r\n");
                        }
#endif
                    }
                    else
                    {
                        updated_filenames.Add(filename);
                    }

                    if (updated_filenames.IndexOf(filename) != -1)
                    {
                        WriteStateFile(strBinDir, "downloading");

                        setProgress?.Invoke(0, 0, 0, "下载 " + strUrl + " 到 " + strLocalFileName + " ...\r\n");

                        var result = await DownloadFileAsync(strUrl,
                                                             strLocalFileName);

                        if (result.Value == -1)
                        {
                            WriteStateFile(strBinDir, "downloadError");
                            return(result);
                        }

                        // 下载成功的本地文件,随时可能被删除,如果整个流程没有完成的话
                        temp_filepaths.Add(strLocalFileName);

                        downloadCount++;
                    }
                }

#if NO
                string strGreenUtilityExe = Path.Combine(strUtilDir, "greenutility.exe");

                if (updated_filenames.IndexOf("greenutility.zip") != -1 ||
                    File.Exists(strGreenUtilityExe) == false)
                {
                    // 将 greenutility.zip 展开到 c:\dp2circulation_temp
                    string strZipFileName = Path.Combine(strBinDir, "greenutility.zip").ToLower();
                    string strTargetDir   = strUtilDir;

                    setProgress?.Invoke(0, 0, 0, "展开文件 " + strZipFileName + " 到 " + strTargetDir + " ...\r\n");
                    try
                    {
                        using (ZipFile zip = ZipFile.Read(strZipFileName))
                        {
                            foreach (ZipEntry e in zip)
                            {
                                e.Extract(strTargetDir, ExtractExistingFileAction.OverwriteSilently);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        string strError = "展开文件 '" + strZipFileName + "' 到目录 '" + strTargetDir + "' 时出现异常" + ex.Message;
                        // 删除文件,以便下次能重新下载和展开
                        try
                        {
                            File.Delete(Path.Combine(strTargetDir, "greenutility.zip"));
                        }
                        catch
                        {
                        }

                        /*
                         * ReportError("dp2circulation 展开 greenutility.zip 时出错", strError);
                         * return;
                         */
                        return(new NormalResult
                        {
                            Value = -1,
                            ErrorInfo = strError
                        });
                    }

                    updated_filenames.Remove("greenutility.zip");
                    temp_filepaths.Remove(strZipFileName);
                }
#endif

                List <string> _updatedGreenZipFileNames = new List <string>();
#if TEST
                // 测试
                this._updatedGreenZipFileNames = new List <string>();
                this._updatedGreenZipFileNames.Add("app.zip");
#else
                // 给 MainForm 一个标记,当它退出的时候,会自动展开 .zip 文件完成升级安装
                _updatedGreenZipFileNames = updated_filenames;
#endif

                WriteStateFile(strBinDir, "downloadComplete");

                if (delayUpdate)
                {
                    if (_updatedGreenZipFileNames.Count > 0)
                    {
                        setProgress?.Invoke(0, 0, 0, "dp2circulation 绿色安装包升级文件已经准备就绪。当退出 dp2circulation 时会自动进行安装。\r\n");
                    }
                    else
                    {
                        setProgress?.Invoke(0, 0, 0, "没有发现更新。\r\n");
                    }

                    temp_filepaths.Clear(); // 这样 finally 块就不会删除这些文件了
                }
                else
                {
                    temp_filepaths.Clear(); // 这样 finally 块就不会删除这些文件了

                    if (_updatedGreenZipFileNames != null && _updatedGreenZipFileNames.Count > 0)
                    {
                        setProgress?.Invoke(0, 0, 0, "正在解压文件");

                        // TODO: 直接解压到目标位置即可
                        string files = StringUtil.MakePathList(_updatedGreenZipFileNames);
                        // 安装软件。用 MoveFileEx 法
                        // return:
                        //      -1  出错
                        //      0   成功。不需要 reboot
                        //      1   成功。需要 reboot
                        int nRet = Install_2(strBinDir,
                                             strBinDir,
                                             files,
                                             Path.GetTempPath(),
                                             out string strError);
                        if (nRet == -1)
                        {
                            // TODO: 这里是否需要删除两个 .zip 文件以便迫使后面重新下载和展开?
                            return(new NormalResult
                            {
                                Value = -1,
                                ErrorInfo = strError
                            });
                        }
                        if (nRet == 1)
                        {
                            WriteStateFile(strBinDir, "waitingReboot");

                            return(new NormalResult
                            {
                                Value = 2   // 表示需要重启计算机
                            });
                        }

                        /*
                         * StartGreenUtility(_updatedGreenZipFileNames,
                         *  strBinDir,
                         *  waitExe);
                         */
                        WriteStateFile(strBinDir, "installed");
                    }
                }
                return(new NormalResult {
                    Value = 1
                });
            }
            finally
            {
                foreach (string filepath in temp_filepaths)
                {
                    File.Delete(filepath);
                }
            }

            /*
             * return;
             * ERROR1:
             * // ShowMessageBox(strError);
             * this.DisplayBackgroundText("绿色更新过程出错: " + strError + "\r\n");
             * ReportError("dp2circulation GreenUpdate() 出错", strError);
             */
        }
Ejemplo n.º 2
0
        // 从 Web 服务器安装或者升级绿色版
        // parameters:
        //      style   处理风格:
        //              delayExtract    是否延迟展开 .zip 文件?
        //              updateGreenSetupExe 是否要一并更新 greensetup.exe?
        //              clearStateFile  处理前是否清除 install_state.txt 文件?(意味着不会受到文件内容为 downloading 的影响)
        // result.Value:
        //      -1  出错
        //      0   经过检查发现没有必要升级
        //      1   成功
        //      2   成功,但需要立即重新启动计算机才能让复制的文件生效
        public static async Task <NormalResult> InstallFromWeb(string downloadUrl,
                                                               string installDirectory,
                                                               string style,
                                                               //bool delayExtract,
                                                               //bool updateGreenSetupExe,
                                                               CancellationToken token,
                                                               Delegate_setProgress setProgress)
        {
            bool delayExtract        = StringUtil0.IsInList("delayExtract", style);
            bool updateGreenSetupExe = StringUtil0.IsInList("updateGreenSetupExe", style);
            bool clearStateFile      = StringUtil0.IsInList("clearStateFile", style);

            string strBaseUrl = downloadUrl;

            if (strBaseUrl[strBaseUrl.Length - 1] != '/')
            {
                strBaseUrl += "/";
            }

            string strBinDir = installDirectory;

            string strUtilDir = GetUtilDir(strBinDir);

            setProgress?.Invoke(-1, -1, -1, "开始自动更新(绿色安装)");

            // 检查状态文件
            // result.Value
            //      -1  出错
            //      0   不存在状态文件
            //      1   正在下载 .zip 过程中。.zip 不完整
            //      2   当前 .zip 和 .exe 已经一样新
            //      3   当前 .zip 比 .exe 要新。需要展开 .zip 进行更新安装
            //      4   下载 .zip 失败。.zip 不完整
            //      5   当前 .zip 比 .exe 要新,需要重启计算机以便展开的文件生效
            var check_result = CheckStateFile(strBinDir);

            if (check_result.Value == -1)
            {
                setProgress?.Invoke(-1, -1, -1, $"检查下载状态时出错: {check_result.ErrorInfo}");
                return(check_result);
            }

            if (clearStateFile && (check_result.Value == 1 || check_result.Value == 3))
            {
                WriteStateFile(strBinDir, null);
                // 继续处理
            }
            else if (check_result.Value == 1 ||
                     check_result.Value == 3 ||
                     check_result.Value == 5)
            {
                if (check_result.Value == 1)
                {
                    setProgress?.Invoke(-1, -1, -1, "前一次下载正在进行,尚未完成。本次下载被放弃");
                }
                if (check_result.Value == 3)
                {
                    setProgress?.Invoke(-1, -1, -1, "前一次下载已经完成,但尚未展开安装。本次下载被放弃");
                }
                if (check_result.Value == 5)
                {
                    setProgress?.Invoke(-1, -1, -1, "前一次下载和安装已经完成,等待计算机重启生效。本次下载被放弃");
                }
                return(new NormalResult());
            }


            // 希望下载的文件。纯文件名
            List <string> filenames = new List <string>()
            {
                // "greenutility.zip", // 这是工具软件,不算在 dp2circulation 范围内
                "app.zip",
                "data.zip"
            };

            if (updateGreenSetupExe)
            {
                filenames.Insert(0, "greensetup.exe");
            }

            // 发现更新了并下载的文件。纯文件名
            List <FileNameAndLength> updated_filenames = new List <FileNameAndLength>();

            // 需要确保最后被展开的文件。如果下载了而未展开,则下次下载的时候会发现文件已经是最新了,从而不会下载,也不会展开。这就有漏洞了
            // 那么就要在下载和展开这个全过程中断的时候,记住删除已经下载的文件。这样可以迫使下次一定要下载和展开
            List <string> temp_filepaths = new List <string>();

            try
            {
                // 第一步,先检查更新的文件,计算需要下载的尺寸
                long downloadLength = 0;
                // List<string> changed_filenames = new List<string>();
                foreach (string filename in filenames)
                {
                    if (token.IsCancellationRequested)
                    {
                        return new NormalResult
                               {
                                   Value     = -1,
                                   ErrorCode = "canceled"
                               }
                    }
                    ;

                    string strUrl = // "http://dp2003.com/dp2circulation/v2/"
                                    strBaseUrl
                                    + filename;
                    string strLocalFileName = Path.Combine(strBinDir, filename).ToLower();

                    // 判断 http 服务器上一个文件是否已经更新
                    // return:
                    //      -1  出错
                    //      0   没有更新
                    //      1   已经更新
                    var result = await GetServerFileInfo(strUrl,
                                                         File.GetLastWriteTimeUtc(strLocalFileName));

                    if (result.Value == -1)
                    {
                        WriteStateFile(strBinDir, "downloadError");

                        return(result);
                    }

                    if (File.Exists(strLocalFileName) == true)
                    {
                        // this.DisplayBackgroundText("检查文件版本 " + strUrl + " ...\r\n");
                        if (result.Value == 1)
                        {
                            updated_filenames.Add(new FileNameAndLength
                            {
                                FileName   = filename,
                                FileLength = result.ContentLength
                            });
                            downloadLength += result.ContentLength;
                        }
                    }
                    else
                    {
                        updated_filenames.Add(new FileNameAndLength
                        {
                            FileName   = filename,
                            FileLength = result.ContentLength
                        });
                        downloadLength += result.ContentLength;
                    }
                }

                // 设置进度条总长度
                setProgress?.Invoke(0, downloadLength, 0, null);

                int  downloadCount = 0;
                long downloaded    = 0;
                foreach (var info in updated_filenames)
                {
                    if (token.IsCancellationRequested)
                    {
                        if (downloadCount > 0)
                        {
                            WriteStateFile(strBinDir, "downloadError");
                        }
                        return(new NormalResult
                        {
                            Value = -1,
                            ErrorCode = "canceled"
                        });
                    }

                    string strUrl = // "http://dp2003.com/dp2circulation/v2/"
                                    strBaseUrl
                                    + info.FileName;
                    string strLocalFileName = Path.Combine(strBinDir, info.FileName).ToLower();

                    // 特殊一点,先下载到一个临时文件名下
                    if (info.FileName == "greensetup.exe")
                    {
                        strLocalFileName = Path.Combine(strBinDir, info.FileName + ".tmp").ToLower();
                    }

                    /*
                     * if (File.Exists(strLocalFileName) == true)
                     * {
                     *  // this.DisplayBackgroundText("检查文件版本 " + strUrl + " ...\r\n");
                     *
                     *  // 判断 http 服务器上一个文件是否已经更新
                     *  // return:
                     *  //      -1  出错
                     *  //      0   没有更新
                     *  //      1   已经更新
                     *  var result = await GetServerFileInfo(strUrl,
                     *      File.GetLastWriteTimeUtc(strLocalFileName));
                     *  if (result.Value == -1)
                     *  {
                     *      if (downloadCount > 0)
                     *          WriteStateFile(strBinDir, "downloadError");
                     *
                     *      return result;
                     *  }
                     *  if (result.Value == 1)
                     *      updated_filenames.Add(filename);
                     #if NO
                     *  else
                     *      this.DisplayBackgroundText("没有更新。\r\n");
                     #endif
                     * }
                     * else
                     *  updated_filenames.Add(filename);
                     */

                    // if (updated_filenames.IndexOf(filename) != -1)
                    {
                        WriteStateFile(strBinDir, "downloading");

                        setProgress?.Invoke(-1, -1, -1, "下载 " + strUrl + " 到 " + strLocalFileName + " ...\r\n");

                        var result = await DownloadFileAsync(strUrl,
                                                             strLocalFileName,
                                                             token,
                                                             (o, e) =>
                        {
                            // 防止越过 Maximum
                            if (downloaded + e.BytesReceived > downloadLength)
                            {
                                downloadLength = downloaded + e.BytesReceived;
                                setProgress?.Invoke(-1, downloadLength, -1, null);
                            }
                            setProgress?.Invoke(-1, -1, downloaded + e.BytesReceived, null);
                        });

                        if (result.Value == -1)
                        {
                            WriteStateFile(strBinDir, "downloadError");
                            return(result);
                        }

                        downloaded += info.FileLength;

                        // 下载成功的本地文件,随时可能被删除,如果整个流程没有完成的话
                        temp_filepaths.Add(strLocalFileName);

                        downloadCount++;
                    }
                }


#if NO
                string strGreenUtilityExe = Path.Combine(strUtilDir, "greenutility.exe");

                if (updated_filenames.IndexOf("greenutility.zip") != -1 ||
                    File.Exists(strGreenUtilityExe) == false)
                {
                    // 将 greenutility.zip 展开到 c:\dp2circulation_temp
                    string strZipFileName = Path.Combine(strBinDir, "greenutility.zip").ToLower();
                    string strTargetDir   = strUtilDir;

                    setProgress?.Invoke(0, 0, 0, "展开文件 " + strZipFileName + " 到 " + strTargetDir + " ...\r\n");
                    try
                    {
                        using (ZipFile zip = ZipFile.Read(strZipFileName))
                        {
                            foreach (ZipEntry e in zip)
                            {
                                e.Extract(strTargetDir, ExtractExistingFileAction.OverwriteSilently);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        string strError = "展开文件 '" + strZipFileName + "' 到目录 '" + strTargetDir + "' 时出现异常" + ex.Message;
                        // 删除文件,以便下次能重新下载和展开
                        try
                        {
                            File.Delete(Path.Combine(strTargetDir, "greenutility.zip"));
                        }
                        catch
                        {
                        }

                        /*
                         * ReportError("dp2circulation 展开 greenutility.zip 时出错", strError);
                         * return;
                         */
                        return(new NormalResult
                        {
                            Value = -1,
                            ErrorInfo = strError
                        });
                    }

                    updated_filenames.Remove("greenutility.zip");
                    temp_filepaths.Remove(strZipFileName);
                }
#endif

                List <string> _updatedGreenZipFileNames = new List <string>();
#if TEST
                // 测试
                this._updatedGreenZipFileNames = new List <string>();
                this._updatedGreenZipFileNames.Add("app.zip");
#else
                List <string> copy_filenames = new List <string>();

                // 给 MainForm 一个标记,当它退出的时候,会自动展开 .zip 文件完成升级安装
                _updatedGreenZipFileNames = new List <string>();
                foreach (var info in updated_filenames)
                {
                    if (info.FileName.EndsWith(".exe") == false)
                    {
                        _updatedGreenZipFileNames.Add(info.FileName);
                    }
                    else
                    {
                        copy_filenames.Add(info.FileName);
                    }
                }
#endif
                if (copy_filenames.Count > 0)
                {
                    foreach (var filename in copy_filenames)
                    {
                        string source = Path.Combine(strBinDir, filename + ".tmp");
                        string target = Path.Combine(strBinDir, filename);

                        try
                        {
                            File.Copy(source, target, true);
                            File.Delete(source);
                        }
                        catch
                        {
                            // TODO: 写入错误日志?
                        }
                    }
                }

                if (downloadCount > 0)
                {
                    WriteStateFile(strBinDir, "downloadComplete");
                }

                // 没有必要升级
                if (_updatedGreenZipFileNames.Count == 0)
                {
                    return(new NormalResult());
                }

                if (delayExtract)
                {
                    if (_updatedGreenZipFileNames.Count > 0)
                    {
                        setProgress?.Invoke(-1, -1, -1, "dp2circulation 绿色安装包升级文件已经准备就绪。当退出 dp2circulation 时会自动进行安装。\r\n");
                    }
                    else
                    {
                        setProgress?.Invoke(-1, -1, -1, "没有发现更新。\r\n");
                    }

                    temp_filepaths.Clear(); // 这样 finally 块就不会删除这些文件了
                }
                else
                {
                    temp_filepaths.Clear(); // 这样 finally 块就不会删除这些文件了

                    if (_updatedGreenZipFileNames != null && _updatedGreenZipFileNames.Count > 0)
                    {
                        setProgress?.Invoke(-1, -1, -1, "正在解压文件");

                        // TODO: 直接解压到目标位置即可
                        string files = StringUtil0.MakePathList(_updatedGreenZipFileNames);
                        // 安装软件。用 MoveFileEx 法
                        // return:
                        //      -1  出错
                        //      0   成功。不需要 reboot
                        //      1   成功。需要 reboot
                        int nRet = Install_2(strBinDir,
                                             strBinDir,
                                             files,
                                             Path.GetTempPath(),
                                             out string strError);
                        if (nRet == -1)
                        {
                            // TODO: 这里是否需要删除两个 .zip 文件以便迫使后面重新下载和展开?
                            return(new NormalResult
                            {
                                Value = -1,
                                ErrorInfo = strError
                            });
                        }
                        if (nRet == 1)
                        {
                            WriteStateFile(strBinDir, "waitingReboot");

                            return(new NormalResult
                            {
                                Value = 2   // 表示需要重启计算机
                            });
                        }

                        /*
                         * StartGreenUtility(_updatedGreenZipFileNames,
                         *  strBinDir,
                         *  waitExe);
                         */
                        WriteStateFile(strBinDir, "installed");
                    }
                }

                return(new NormalResult {
                    Value = 1
                });
            }
            catch (Exception ex)
            {
                WriteStateFile(strBinDir, "downloadError");
                return(new NormalResult
                {
                    Value = -1,
                    ErrorInfo = $"exception: {ex.Message}"
                });
            }
            finally
            {
                foreach (string filepath in temp_filepaths)
                {
                    File.Delete(filepath);
                }
            }

            /*
             * return;
             * ERROR1:
             * // ShowMessageBox(strError);
             * this.DisplayBackgroundText("绿色更新过程出错: " + strError + "\r\n");
             * ReportError("dp2circulation GreenUpdate() 出错", strError);
             */
        }