Ms word 从VSTO加载项检测Word 2016中的文本更改
这个问题与Windows 10中运行的Word 2016在Visual Studio(Professional)2015中的开发密切相关(事实上包括该问题答案中的示例代码) 我试图检测Word文档中的文本何时从VSTO加载项发生更改。我从Ms word 从VSTO加载项检测Word 2016中的文本更改,ms-word,vsto,visual-studio-2015,office-addins,Ms Word,Vsto,Visual Studio 2015,Office Addins,这个问题与Windows 10中运行的Word 2016在Visual Studio(Professional)2015中的开发密切相关(事实上包括该问题答案中的示例代码) 我试图检测Word文档中的文本何时从VSTO加载项发生更改。我从 (2011年11月14日) (2012年10月21日) (2012年10月24日) (2012年11月5日) 没有事件驱动的方法来实现这一点。文本更改时Word不会发送事件 我已经讨论了两种变通方法: 使用事件。不幸的是,当通过按箭头键、使用鼠标、执行撤消
- (2011年11月14日)
- (2012年10月21日)
- (2012年10月24日)
- (2012年11月5日)
使用系统;
使用系统诊断;
使用System.Runtime.InteropServices;
使用系统线程;
使用System.Windows.Forms;
名称空间关键字DownWordAddin
{
公共部分类ThisAddIn
{
专用常量int WH_键盘LL=13;
私有常量int WM_KEYDOWN=0x0100;
私有静态IntPtr hookId=IntPtr.Zero;
私有委托IntPtr HookProcedure(intncode、IntPtr wParam、IntPtr lParam);
私有静态HookProcedure=HookCallback;
[DllImport(“kernel32.dll”,CharSet=CharSet.Auto,SetLastError=true)]
私有静态外部IntPtr GetModuleHandle(字符串lpModuleName);
[DllImport(“user32.dll”,SetLastError=true)]
私有静态外部bool unhookwindowshookx(IntPtr hhk);
[DllImport(“user32.dll”,CharSet=CharSet.Auto,SetLastError=true)]
私有静态外部IntPtr SetWindowsHookEx(intidhook、HookProcedure lpfn、IntPtr hMod、uint dwThreadId);
[DllImport(“user32.dll”,CharSet=CharSet.Auto,SetLastError=true)]
私有静态外部IntPtr CallNextHookEx(IntPtr hhk、intncode、IntPtr wParam、IntPtr lParam);
私有静态IntPtr SetHook(HookProcedure)
{
使用(Process=Process.GetCurrentProcess())
使用(ProcessModule=process.MainModule)
返回SetWindowsHookEx(WH_KEYBOARD,procedure,GetModuleHandle(module.ModuleName),0);
}
专用静态IntPtr钩子回调(int nCode、IntPtr wParam、IntPtr lParam)
{
如果(nCode>=0&&wParam==(IntPtr)WM\u KEYDOWN)
{
int pointerCode=Marshal.ReadInt32(LPRAM);
字符串按键=((键)指针代码).ToString();
//对按键进行某种处理。
变量线程=新线程(()=>{
Debug.WriteLine(按键);
});
thread.Start();
}
返回CallNextHookEx(hookId、nCode、wParam、lParam);
}
私有void ThisAddIn_启动(对象发送方,事件参数e)
{
hookId=SetHook(程序);
}
私有void ThisAddIn\u关闭(对象发送方,事件参数e)
{
UnhookWindowsHookEx(hookId);
}
#区域VSTO生成的代码
///
///设计器支持所需的方法。
///
私有void InternalStartup()
{
this.Startup+=new System.EventHandler(ThisAddIn\u启动);
this.Shutdown+=new System.EventHandler(ThisAddIn\u Shutdown);
}
#端区
}
}
当我使用此加载项运行Word 2016时,我会看到键控事件发送到边缘浏览器甚至Visual Studio,但不会发送到Word本身
Word 2016中是否以某种方式阻止了键控挂钩,或者我做错了什么?我在Word 2013中也遇到过同样的问题,必须想出一个有点“创造性”的解决方案。它用于监视活动文档文本中的更改,并在更改时触发事件。这并不理想,但我们做了我们必须做的事情来让事情顺利进行
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Word;
using System.ComponentModel;
namespace WordUtils {
public class TextChangeDetector {
public Word.Application Application;
private BackgroundWorker bg;
public delegate void TextChangeHandler(object sender, TextChangedEventArgs e);
public event TextChangeHandler OnTextChanged;
public TextChangeDetector(Word.Application app) {
this.Application = app;
}
public void Start() {
bg = new BackgroundWorker();
bg.WorkerReportsProgress = true;
bg.WorkerSupportsCancellation = true;
bg.ProgressChanged += bg_ProgressChanged;
bg.DoWork += bg_DoWork;
bg.RunWorkerAsync(this.Application);
}
private void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) {
switch (e.ProgressPercentage) {
case 50: //change
if (OnTextChanged != null) {
OnTextChanged(this, new TextChangedEventArgs((char)e.UserState));
}
break;
}
}
private void bg_DoWork(object sender, DoWorkEventArgs e) {
Word.Application wordApp = e.Argument as Word.Application;
BackgroundWorker bg = sender as BackgroundWorker;
string lastPage = string.Empty;
while (true) {
try {
if (Application.Documents.Count > 0) {
if (Application.ActiveDocument.Words.Count > 0) {
var currentPage = Application.ActiveDocument.Bookmarks["\\Page"].Range.Text;
if (currentPage != null && currentPage != lastPage) {
var differ = new DiffPlex.Differ();
var builder = new DiffPlex.DiffBuilder.InlineDiffBuilder(differ);
var difference = builder.BuildDiffModel(lastPage, currentPage);
var change = from d in difference.Lines where d.Type != DiffPlex.DiffBuilder.Model.ChangeType.Unchanged select d;
if (change.Any()) {
bg.ReportProgress(50, change.Last().Text.Last());
}
lastPage = currentPage;
}
}
}
} catch (Exception) {
}
if (bg.CancellationPending) {
break;
}
System.Threading.Thread.Sleep(100);
}
}
public void Stop() {
if (bg != null && !bg.CancellationPending) {
bg.CancelAsync();
}
}
}
public class TextChangedEventArgs : EventArgs {
public char Letter;
public TextChangedEventArgs(char letter) {
this.Letter = letter;
}
}
}
用法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Word;
using WordUtils;
namespace WordAddIn1 {
public partial class ThisAddIn {
TextChangeDetector detector;
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
detector = new TextChangeDetector(Application);
detector.OnTextChanged += detector_OnTextChanged;
detector.Start();
}
void detector_OnTextChanged(object sender, TextChangedEventArgs e) {
Console.WriteLine(e.Letter);
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e) {
detector.Stop();
}
#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);
}
#endregion
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Xml.Linq;
使用Word=Microsoft.Office.Interop.Word;
使用Office=Microsoft.Office.Core;
使用Microsoft.Office.Tools.Word;
使用WordUtils;
名称空间WordAddIn1{
公共部分类ThisAddIn{
文本转换检测器;
私有void ThisAddIn_启动(对象发送方,System.EventArgs e){
检测器=新的TextChangeDetector(应用);
detector.OnTextChanged+=detector\u OnTextChanged;
检测器。启动();
}
无效检测器\u OnTextChanged(对象发送器,textchangedventargs e){
控制台写线(e.Letter);
}
私有void ThisAddIn_关闭(对象发送方,System.EventArgs e){
检测器。停止();
}
#区域VSTO生成的代码
///
///设计器支持所需的方法-不修改
///此方法的内容与代码编辑器一起使用。
///
私有void InternalStartup(){
this.Startup+=new System.EventHandler(ThisAddIn\u启动);
this.Shutdown+=new System.EventHandler(ThisAddIn\u Shutdown);
}
#端区
}
}
如果不在VSTO加载项中使用低级钩子,则所有操作都应该正常工作
[DllImport(“kernel32”,CharSet=CharSet.Auto,SetLastError=true)]
public static extern int GetCurrentThreadId();
const int WH_键盘=2;
私有静态IntPtr SetHook(HookProc