using System; using System.Collections.Generic; using System.IO; using DCIT.Core.Models; namespace DCIT.Core.Services { public class RuntimeEnvironmentValidationService { private static readonly string[] WpsProgIds = { "KWPS.Application", "kwps.Application", "WPS.Application", "wps.Application", }; private readonly string _startupDirectory; public RuntimeEnvironmentValidationService(string startupDirectory = null) { _startupDirectory = string.IsNullOrWhiteSpace(startupDirectory) ? AppContext.BaseDirectory : startupDirectory; } public RuntimeEnvironmentValidationResult Validate() { var result = new RuntimeEnvironmentValidationResult { StartupDirectory = _startupDirectory, }; result.IsStartupDirectoryWritable = CanWriteToDirectory(_startupDirectory); if (!result.IsStartupDirectoryWritable) { result.BlockingIssues.Add("程序启动目录不可写。请将程序部署到当前用户具有写权限的目录后再启动。"); } result.ResolvedAutomationProgId = ResolveAutomationProgId(); if (string.IsNullOrWhiteSpace(result.ResolvedAutomationProgId)) { result.BlockingIssues.Add("未检测到可自动化的 Microsoft Word 或 WPS 组件。当前环境无法满足目录/域刷新及 .doc 处理要求。"); } result.ResolvedDocToPath = ResolveDocToPath(); if (string.IsNullOrWhiteSpace(result.ResolvedDocToPath)) { result.Warnings.Add("未检测到 docto.exe,.doc 兼容性将仅依赖 Word/WPS 自动化链路。"); } return result; } protected virtual IEnumerable GetOfficeAutomationProgIds() { yield return "Word.Application"; foreach (var progId in WpsProgIds) { yield return progId; } } protected virtual bool IsProgIdRegistered(string progId) { return !string.IsNullOrWhiteSpace(progId) && Type.GetTypeFromProgID(progId, false) != null; } protected virtual string ResolveDocToPath() { var candidates = new List(); var envPath = Environment.GetEnvironmentVariable("DCIT_DOCTO_PATH"); if (!string.IsNullOrWhiteSpace(envPath)) { candidates.Add(envPath); } candidates.Add(Path.Combine(_startupDirectory, "docto.exe")); candidates.Add(Path.Combine(_startupDirectory, "tools", "DocTo", "docto.exe")); foreach (var candidate in candidates) { if (!string.IsNullOrWhiteSpace(candidate) && File.Exists(candidate)) { return candidate; } } var pathEnv = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; foreach (var segment in pathEnv.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { try { var candidate = Path.Combine(segment.Trim(), "docto.exe"); if (File.Exists(candidate)) { return candidate; } } catch { } } return null; } protected virtual bool CanWriteToDirectory(string directoryPath) { if (string.IsNullOrWhiteSpace(directoryPath)) { return false; } try { Directory.CreateDirectory(directoryPath); var probePath = Path.Combine(directoryPath, ".dcit-writecheck-" + Guid.NewGuid().ToString("N") + ".tmp"); File.WriteAllText(probePath, "probe"); File.Delete(probePath); return true; } catch { return false; } } private string ResolveAutomationProgId() { foreach (var progId in GetOfficeAutomationProgIds()) { if (IsProgIdRegistered(progId)) { return progId; } } return null; } } }