/// <summary>
        /// 发布BIN目录.(在编译项目之后调用)
        /// sourcebinDir参数为项目根目录起始的相对目录路径 如 bin/debug(正斜杠,后面无/)
        /// </summary>
        /// <param name="sourcebinDir"></param>
        internal static string PublishBin(string sourcebinDir)
        {
            try
            {
                // 源bin目录全路径
                string fromBinDir = $"{EnvVar.ProjectDir}/{sourcebinDir}";

                // 目标bin目录
                string targetDir = $"{JsonCfg.DistDir}/bin/";

                // 源bin目录下所有文件
                string[] binFiles = Directory.GetFiles(fromBinDir, "*", SearchOption.AllDirectories);

                // vs输出窗口显示信息
                StringBuilder info = new StringBuilder();
                info.AppendLine($"START: 开始发布bin目录:------");
                info.AppendLine($"从: {fromBinDir} 到: {targetDir}");

                for (int i = 0; i < binFiles.Length; i++)
                {
                    string itemPath   = binFiles[i];
                    string targetPath = itemPath.Replace(fromBinDir, targetDir);
                    // 目标路径目录如果不存在,则建立之.
                    string targetFileDir = Path.GetDirectoryName(targetPath);
                    Directory.CreateDirectory(targetFileDir);
                    //
                    File.Copy(itemPath, targetPath, true);
                    info.AppendLine($"{i + 1} 已发布 {targetPath}");
                }
                info.AppendLine($"END: bin目录文件发布结束.总共[ {binFiles.Length} ]个...");
                //
                OutPutInfo.VsOutWind(info.ToString());
                return(null);
            }
            catch (Exception e)
            {
                return($"ERR: bin目录发布时发生异常:{Environment.NewLine}{e}{Environment.NewLine}");
            }
        }
        /// <summary>
        /// 将文件发布到目录,根据指定的配置.
        /// 成功返回null.失败返回出错信息
        /// </summary>
        /// <param name="filesPath"></param>
        internal static string PublishFiles(List <string> filesPath)
        {
            // 建立发布目录
            string outDir = CreateOutDir();

            if (outDir != null)
            {
                return(outDir);
            }

            // 使用预定规则,选出符合发布要求的文件
            List <string> files = FilterFiles(filesPath);

            if (files.Count == 0)
            {
                return("没有找到符合发布要求的文件");
            }

            // vs输出窗口日志信息
            StringBuilder info = new StringBuilder();

            info.AppendLine($"START: 开始发布文件------");

            // 按预定规则发布文件
            for (int i = 0; i < files.Count; i++)
            {
                string itemPath = files[i];

                // 计算并生成目标路径目录
                string targetPath = TargetPath(itemPath, JsonCfg.DistDir);

                // 发布文件
                string resFile = OutPutFile(itemPath, targetPath);
                info.AppendLine($"\t{i + 1}. {targetPath} {resFile}");
            }
            info.AppendLine($"END: 发布结束.总共[ {files.Count} ]个...");
            OutPutInfo.VsOutWind(info.ToString());
            return(null);
        }
        /// <summary>
        /// This function is the callback used to execute the command when the menu item is clicked.
        /// See the constructor to see how the menu item is associated with this function using
        /// OleMenuCommandService service and MenuCommand class.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private void Execute(object sender, EventArgs e)
        {
            //ThreadHelper.ThrowIfNotOnUIThread();
            // 当前活动项目路径
            Project activeProj = ProjectHelpers.GetActiveProject();

            if (activeProj == null)
            {
                OutPutInfo.Info("未选中WEB项目"); return;
            }
            // 建立发布配置对象
            EnvVar.ProjectDir = activeProj.GetRootFolder();
            string res = PublishHelpers.CreatePublishCfg();

            if (res != null)
            {
                OutPutInfo.Info(res); return;
            }

            // 发布前删除发布目录下所有文件(根据配置文件的设置而执行)
            string emptyOutDir = PublishHelpers.EmptyPuslishDir();

            if (emptyOutDir != null)
            {
                OutPutInfo.Info(emptyOutDir); return;
            }

            //
            OutPutInfo.VsOutWind("<<<--发布项目-->>>" + Environment.NewLine, true);

            // 如果要发布bin目录,才编译项目
            if (PublishHelpers.JsonCfg.BuildBin == true)
            {
                // 编译项目. buildCfg : debug和release.取自当前选中的编译选项
                string buildCfg = activeProj.ConfigurationManager.ActiveConfiguration.ConfigurationName;
                EnvVar._dte.Solution.SolutionBuild.BuildProject(buildCfg, activeProj.UniqueName, true);
                // 编译后DLL文件所在目录.是一个相对于项目根目录起始的目录
                string outBinDir = activeProj.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString().Replace('\\', '/').Trim('/');

                // 复制dll文件到目标目录
                string resBin = PublishHelpers.PublishBin(outBinDir);
                if (resBin != null)
                {
                    OutPutInfo.Info(resBin); return;
                }
            }

            // 发布项目文件
            // 取得项目中所有文件
            List <string> srcfiles = activeProj.GetItems();

            if (srcfiles.Count == 0)
            {
                OutPutInfo.Info("未发布文件,没有找到适合发布的文件.");
                return;
            }

            // 发布处理
            Task.Factory.StartNew(() =>
            {
                string resinfo = PublishHelpers.PublishFiles(srcfiles);
                if (resinfo != null)
                {
                    OutPutInfo.Info(resinfo);
                }
            });
        }