callmeyan 8284a9d552 break: ActiveDocument 改为实时获取
优化调试逻辑,增强日志记录,简化代码结构

- 修改 AIProofread.csproj.user 的 <StartAction> 配置,调试时直接启动项目。
- Bridge.cs 中增加异常处理的详细错误信息。
- DocumentInfo.cs 增加日志记录,调整 RunInMainThread 方法逻辑。
- DocumentList.cs 删除过时的 XML 注释。
- ThisAddIn.cs 优化文档管理逻辑,调整 ActiveDocument 属性为只读,改进文档列表处理,删除冗余代码。
2025-05-09 16:59:27 +08:00

749 lines
25 KiB
C#

using System;
using Newtonsoft.Json;
using System.Threading;
using Microsoft.Office.Interop.Word;
using System.Windows.Forms;
using System.IO;
using AIProofread.Controls;
using UtilLib;
using AIProofread.Model;
using System.Collections.Generic;
using log4net;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.EMMA;
namespace AIProofread
{
public partial class ThisAddIn
{
// LogManager.GetLogger(typeof(ThisAddIn))
public ILog Logger = LogHelper.GetLogger(typeof(ThisAddIn));
public static SynchronizationContext FmainThreadContext;
public string AddinName = " ";
/// <summary>
/// 最小宽度
/// </summary>
public static int MinWidth = 0;
/// <summary>
/// 启动路径
/// </summary>
public string applicationStartupPath;
/// <summary>
/// 校对面板
/// </summary>
public ProofreadMainControl proofreadPanel;
/// <summary>
/// 工具栏
/// </summary>
public Ribbon1 ribbon;
/// <summary>
/// 当前word application
/// </summary>
public static Microsoft.Office.Interop.Word.Application CurrentWordApplication;
///// <summary>
///// 智能标记集合
///// </summary>
//internal SmartTagCollection VstoSmartTags;
/// <summary>
/// 所有文档信息
/// </summary>
public DocumentList documentList = new DocumentList();
/// <summary>
/// 当前文档信息
/// </summary>
public DocumentInfo ActiveDocument
{
get
{
return documentList.SetActiveDocument(Application.ActiveDocument);
}
}
/// <summary>
/// 智能常识检测对话框 = new FormCommonsenseDetection()
/// </summary>
public FormCommonsenseDetection formCommonsenseDetection;
/// <summary>
/// 是否为wps
/// </summary>
public bool IsWPS { get; set; }
public List<FormLogin> LoginFormList = new List<FormLogin>();
public static bool AppRunning = true;
private System.Timers.Timer _timer;
//public override void BeginInit()
//{
// base.BeginInit();
// CurrentWordApplication = Application;
// CurrentWordApplication.DocumentChange += CurrentWordApplication_DocumentChange;
//}
public void ShowDetection()
{
if (formCommonsenseDetection == null || formCommonsenseDetection.IsDisposed)
{
formCommonsenseDetection = new FormCommonsenseDetection();
}
//formCommonsenseDetection.ShowInTaskbar = true;
formCommonsenseDetection.Show();
// 显示在最前面
formCommonsenseDetection.Activate();
}
public void HideDetection()
{
formCommonsenseDetection.Close();
formCommonsenseDetection = null;
}
private void ProcessApplicationException(object sender, UnhandledExceptionEventArgs e)
{
Logger.Error("UnhandledException", e.ExceptionObject as Exception);
}
private void ProcessApplicationFormException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Logger.Error("ProcessApplicationFormException", e.Exception);
}
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
try
{
InitDeviceId();
AppInitialize();
//formCommonsenseDetection.ShowInTaskbar = false;
//formCommonsenseDetection.Show();
Logger.Debug("ThisAddIn_Startup Platform --> " + (IsWPS ? "WPS" : "WORD"));
// 捕获全局异常
AppDomain.CurrentDomain.UnhandledException += ProcessApplicationException;
System.Windows.Forms.Application.ThreadException += ProcessApplicationFormException;
// 处理文档事件
Application.DocumentOpen += Application_DocumentOpen;
Application.DocumentBeforeClose += Application_DocumentBeforeClose;
Application.WindowActivate += Application_WindowActivate;
//Application.WindowDeactivate += Application_WindowDeactivate;
Application.DocumentBeforeSave += Application_DocumentBeforeSave;
(Application as ApplicationEvents4_Event).NewDocument += Application_NewDocument;
Application.DocumentChange += Application_DocumentChange;
// 选区发生变化事件
this.Application.WindowSelectionChange += Application_WindowSelectionChange;
//CheckPluginUpgradeInfo();
// CheckDocumentClosedTick();
// 定时检测文档是否关闭
//_timer = new System.Timers.Timer(10000);
//_timer.Elapsed += CheckDocumentClosed;
//_timer.AutoReset = true;
//_timer.Enabled = true;
try
{
// 默认已经打开了文档 直接初始化
if (Application.Documents.Count > 0 && Application.ActiveDocument != null)
{
Logger.Debug("ThisAddIn_Startup 开始初始化当前文档");
documentList.InitDocument(Application.ActiveDocument);
// 直接初始化面板
// info.CheckPanel();
Logger.Debug("ThisAddIn_Startup 结束初始化当前文档");
}
}
catch (Exception ex)
{
Logger.Error("Initialize documentlist Error ", ex);
}
}
catch (Exception ex1)
{
Logger.Error("Startup Error", ex1);
}
}
private void Application_DocumentBeforePrint(Document Doc, ref bool Cancel)
{
throw new NotImplementedException();
}
// 异步获取设备唯一标识
public void InitDeviceId()
{
System.Threading.Tasks.Task.Run(() =>
{
try
{
var deviceId = Tools.GetDeviceId();
if (string.IsNullOrEmpty(deviceId))
{
deviceId = Tools.GetDeviceId();
}
if (!string.IsNullOrEmpty(deviceId))
{
Config.DeviceId = deviceId;
Logger.Info("设备唯一标识:" + deviceId);
}
}
catch (Exception ex)
{
Logger.Error("InitDeviceId Error:", ex);
}
});
}
public void CheckDocumentClosed(object sender, System.Timers.ElapsedEventArgs e)
{
var existsList = new List<Document>();
try
{
var docList = CurrentWordApplication.Documents;
if (documentList.Count == 0 || docList.Count == existsList.Count) return;
existsList.Clear();
foreach (Document item in docList)
{
existsList.Add(item);
}
// 检测文档是否关闭
for (int i = documentList.documentList.Count - 1; i >= 0; i--)
{
var item = documentList.documentList[i];
// 判断文档对象是否已经被移除
if (item.CurrentDocument == null)
{
documentList.Remove(item);
continue;
}
// 可能出现另存问题 所以需要更新文件名称
//var oldName = item.fileName;
//var currentName = item.CurrentDocument.FullName;
//if (oldName != currentName)
//{
// item.fileName = currentName;
//}
if (!existsList.Contains(item.CurrentDocument))
{
Logger.Debug("检测到文档关闭,已移除:" + item.fileName);
try
{
item.RunInMainThread(() =>
{
item.Dispose();
}, true);
}
catch (Exception ex1)
{
Logger.Error("移除已关闭文档->释放面板", ex1);
}
try
{
documentList.Remove(item);
}
catch (Exception ex2)
{
Logger.Error("移除已关闭文档", ex2);
}
}
}
}
catch (Exception ex)
{
Logger.Error("检测已关闭文档", ex);
}
//await System.Threading.Tasks.Task.Run(() =>
// {
//
// while (AppRunning)
// {
// Thread.Sleep(10000); // 暂停10s
// }
// });
}
async void CheckPluginUpgradeInfo()
{
await System.Threading.Tasks.Task.Run(() =>
{
try
{
// 检测升级信息
Bridge.bridge.CheckPluginUpgrade();
}
catch (Exception ex)
{
Logger.Error("检测升级信息异常: ", ex);
}
});
}
private void Application_DocumentBeforeSave(Document originDocument, ref bool SaveAsUI, ref bool Cancel)
{
//LogHelper.Log("DocumentSave", originDocument.Name + "\r\n");
if (CurrentWordApplication.Documents.Count == 0)
{
return;
}
//if (ActiveDocument == null) return;
//// TODO 完成缓存保存
}
//public DocumentInfo ActiveDocument()=> documentList.GetActiveDocument();
private void AppInitialize()
{
CurrentWordApplication = Application;
// 初始化配置
InitAppByConfig();
// 主线程
FmainThreadContext = SynchronizationContext.Current;
// 启动地址
applicationStartupPath = System.Windows.Forms.Application.StartupPath;
Logger.Debug("applicationStartupPath --> " + applicationStartupPath);
// 判断是否是WPS
if (applicationStartupPath.Contains("WPS"))
{
Config.IS_WPS = true;
IsWPS = true;
try
{
Globals.Ribbons.Ribbon1.InitWPS();
}
catch (Exception ex)
{
Logger.Error("Init WPS Error ", ex);
}
}
//string verTextFile = Config.APP_BASE_DIR + Path.GetFileName("app_version.txt");
//try
//{
// File.WriteAllText(verTextFile, Config.APP_VERSION);
//}
//catch (Exception ex)
//{
// Logger.Error("Write App Version Error ", ex);
//}
Logger.Info("init " + (Config.IS_WPS ? "WPS" : "WORD") + " end");
}
private void InitAppByConfig()
{
try
{
if (File.Exists(Config.CONFIG_FILE))
{
string content = File.ReadAllText(Config.CONFIG_FILE);
//LogHelper.Log("INIT", "Found app.json " + content);
if (content == null || content.Length == 0) return;
AppConfig config = JsonConvert.DeserializeObject<AppConfig>(content);
// 插件网址
if (!string.IsNullOrEmpty(config.AppUrl))
{
Config.WEB_PATH = config.AppUrl;
}
// 运行环境
if (!string.IsNullOrEmpty(config.Environment))
{
Config.APP_ENV = config.Environment == "dev" ? AppEnvironment.Dev : (
config.Environment == "test" ? AppEnvironment.Test : AppEnvironment.Prod
);
}
Config.RUN_IN_DEBUG = config.AppRunInDebug;
//if (Config.APP_ENV != AppEnvironment.Prod && this.ribbon != null)
//{
// this.ribbon.Ini();
//}
}
}
catch (Exception) { }
}
private void Application_DocumentChange()
{
// 检测是否存在打开的文档
if (CurrentWordApplication.Documents.Count == 0)
{
return;
}
var currentDocument = CurrentWordApplication.ActiveDocument;
Logger.Debug("DocumentChange => " + currentDocument.Name);
CheckDocumentClosed(null, null);
if (formCommonsenseDetection != null)
{
formCommonsenseDetection.SendMessageToWeb("document-change", null);
}
if (InDocumentInList(currentDocument))
{
documentList.InitDocument(currentDocument);
}
//var document = documentList.InitDocument(CurrentWordApplication.ActiveDocument);
//if (document == null) return;
}
private void Application_WindowDeactivate(Document doc, Window Wn)
{
//Logger.Log("Application_WindowDeactivate -- " + doc.FullName + " visible:");
//HidePanel(Doc);
// 处理wps直接资源管理器新开文档面板闪烁问题
//if (IsWPS) {
// this.currentDocumentTaskPane.Visible = false;
//}
}
/// <summary>
/// 判断当前文档是否在列表中
/// </summary>
/// <param name="doc"></param>
/// <returns></returns>
private bool InDocumentInList(Document doc)
{
if (doc == null) return false;
foreach (Document item in Application.Documents)
{
if (item == doc)
{
return true;
}
}
return false;
}
/// <summary>
/// 激活文档
/// </summary>
/// <param name="activeDoc"></param>
/// <param name="Wn"></param>
private void Application_WindowActivate(Document activeDoc, Window Wn)
{
Logger.Debug("WindowActivate -- " + activeDoc.Name);
if (activeDoc != null && InDocumentInList(activeDoc))
{
Logger.Debug("DocumentChange -- " + activeDoc.Name
+ " 修订模式: is " + activeDoc.TrackRevisions
+ ActiveDocument?.CurrentDocument?.Name + "==》" + activeDoc.Name);
documentList.SetActiveDocument(activeDoc);
//// 设置当前文档
//ActiveDocument = document;
}
//// 当前文档添加书签集合
//if (!allMarks.ContainsKey(activeDoc))
//{
// allMarks[activeDoc] = new Dictionary<int, ProofreadItem>();
//}
////ShowPanel(Doc);
//// 创建面板
//if (!taskPanels.ContainsKey(activeDoc))
//{
// ShowPanel(activeDoc, false);
// panelsVisibleStatus.Add(activeDoc, false);
//}
//// 设置当前面板为新创建的面板
//this.currentDocumentTaskPane = taskPanels[activeDoc];
//if (IsWPS)
//{
// HideOtherPanel(activeDoc);
//}
//if (panelsVisibleStatus.ContainsKey(activeDoc) && panelsVisibleStatus[activeDoc])
//{
// taskPanels[activeDoc].Visible = true;
//}
}
/// <summary>
/// 关闭文档
/// </summary>
/// <param name="currentDoc"></param>
/// <param name="Cancel"></param>
private void Application_DocumentBeforeClose(Document currentDoc, ref bool Cancel)
{
Logger.Debug("will close " + currentDoc.Name);
var doc = documentList.Get(currentDoc);
if (Config.IS_WPS && doc != null)
{
doc.HidePane();
}
}
//public void ActiveCurrentDocumentMarks(Document document)
//{
// // 判断是否存在 没有的话初始化
// var currentDoc = document ?? Application.ActiveDocument ;
// if (!allMarks.ContainsKey(currentDoc))
// {
// allMarks[currentDoc] = new Dictionary<int, ProofreadItem>();
// }
// Bridge.marks = allMarks[currentDoc];
//}
private void Application_NewDocument(Document doc)
{
//LogHelper.Log("NewDocument" + doc.Name);
}
private void Application_DocumentOpen(Document doc)
{
//LogHelper.Log("DocumentOpen " + doc.Name);
}
public int GetMinWidth()
{
return MinWidth;
}
public void Send(SendOrPostCallback d)
{
FmainThreadContext.Send(d, null);
}
private void Application_WindowSelectionChange(Selection s)
{
// 处理当前文档选区,用于判断是否显示常识性检测
ribbon.ParseSelectionChange(s);
if (ActiveDocument == null || !s.Active) return;
// 当前选区是否存在书签
if (s.Range.Start != s.Range.End || s.Bookmarks.Count == 0) return;
var bookmarks = s.Bookmarks;
// 获取当前选区书签的起始位置
var currentPosition = s.Range.Start;
// Logger.Info("当前选区书签数量: " + s.Bookmarks.Count);
// 遍历书签 找到所需的书签
foreach (Bookmark item in s.Bookmarks)
{
// 判断书签的选区不包含当前选中区域
if (currentPosition < item.Range.Start || currentPosition > item.Range.End)
{
ReleaseComObject(item);
continue;
}
Logger.Debug("当前选区书签名称: " + item.Name + "范围:" + item.Range.Start + "," + item.Range.End);
//Logger.Debug("当前选区书签内容: " + item.Range.Text);
// 获取书签id
int proofreadId = Config.GetBookmarkIdByName(item.Name);
// 释放com对象
ReleaseComObject(item);
Logger.Debug("当前选区proofreadId: " + proofreadId);
if (proofreadId > 0)
{
//var targetRange = item.Range;
//// 选中
//targetRange.Select();
//Globals.ThisAddIn.Application.ActiveWindow.ScrollIntoView(targetRange);
// 只选择第一个书签
ActiveDocument?.SelectMarkById(proofreadId, true);
ReleaseComObject(bookmarks);
return;
}
//
}
ReleaseComObject(bookmarks);
//Bridge.bridge.SelectMarkById(-1, 0);
}
// 释放COM对象
private void ReleaseComObject(object obj)
{
if (obj != null)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
}
catch (Exception ex)
{
Logger.Error("ReleaseComObject Error", ex);
}
finally
{
obj = null;
}
}
}
public void SendMessageToWeb(string msg, object data)
{
// 先显示panel
//var panel = this.ShowPanel(Application.ActiveDocument, true);
//SendMessageToWeb(panel.Control, msg, data);
ActiveDocument?.SendMessageToWeb(msg, data);
}
public void GlobalCallback(string callbackId, string result)
{
documentList.SetActiveDocument(Application.ActiveDocument)?.GlobalCallback(callbackId, result);
}
// 显示面板
public void ShowPanel()
{
documentList.SetActiveDocument(Application.ActiveDocument)?.ShowPane();
}
// 隐藏面板
public void HidePanel()
{
documentList.SetActiveDocument(Application.ActiveDocument)?.HidePane();
}
/// <summary>
/// 隐藏所有面板
/// </summary>
public void HideAllPanel()
{
this.documentList.HideAllPane();
}
/// <summary>
/// 显示登录窗口
/// </summary>
/// <param name="action"></param>
public void ShowLoginForm(string action)
{
// 关闭之前的窗口
//if(LoginFormList.Count > 0){
// LoginFormList.ForEach(f => f.Close());
//}
//LoginFormList.Add(frm);
ActiveDocument?.ShowLogin(action);
}
/// <summary>
/// 清理所有面板
/// </summary>
//void ClearPanels()
//{
// taskPanels.Values.ToList().ForEach(p =>
// {
// try
// {
// p.Dispose();
// }
// catch (Exception ex)
// {
// Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
// Logger.Log(ex.Message + "\n" + ex.StackTrace);
// }
// });
// taskPanels.Clear();
//}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
// 取消捕获全局异常事件
AppDomain.CurrentDomain.UnhandledException -= ProcessApplicationException;
System.Windows.Forms.Application.ThreadException -= ProcessApplicationFormException;
Logger.Debug("shutdown");
documentList.Clear();
if (_timer != null)
{
_timer.Stop();
}
}
public void SyncLogout()
{
ribbon.ProcessLogout();
//taskPanels.Values.ToList().ForEach(p =>
//{
// try
// {
// // 同步登录失败信息
// SendMessageToWeb(p.Control, "async-logout", null);
// }
// catch (Exception ex)
// {
// Logger.Log("async-logout:", ex);
// }
//});
}
public void SetDocumentId(Document document, int id)
{
var doc = documentList.Get(document);
if (doc != null) doc.Id = id;
}
public DocumentInfo GetDocumentById(int id)
{
return id <= 0 ? ActiveDocument : documentList.GetById(id);
}
/// <summary>
/// 清除所有标记
/// </summary>
public void ClearAllProofreadMark()
{
ActiveDocument?.ClearAllProofreadMark();
//Globals.ThisAddIn.SendMessageToWeb("clear-tips", null);
}
public void ShowDialog(string message, string confirmText, string confirmAction)
{
ActiveDocument?.ShowDialog(message, confirmText, confirmAction);
}
public void ShowMessage(string message, int closeDelay)
{
ActiveDocument?.ShowMessage(message, closeDelay);
}
//public string LoadCacheByPath()
//{
//}
//public void SaveCache(string cache)
//{
//}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
public void InitProofreadCacheList(List<CorrectContext> list, Dictionary<int, ProofreadRangeInfo> dics)
{
ActiveDocument?.InitProofreadCache(list, dics);
}
#endregion
}
}