C#:Excel 2007 插件,如何挂钩 Windows 激活和停用事件

Posted

技术标签:

【中文标题】C#:Excel 2007 插件,如何挂钩 Windows 激活和停用事件【英文标题】:C#: Excel 2007 Addin, How to Hook Windows Activate and Deactivate Events 【发布时间】:2009-07-03 12:36:35 【问题描述】:

我正在编写一个 Excel 2007 插件。使用 VS2008 和 .net 3.5,C#。

我捕获了 Microsoft.Office.Interop.Excel.Application 的 WindowActivate 和 WindowDeActivate 事件。

令人惊讶的是,WindowActivate 和 Deactivate 仅在我在两个 Excel 窗口之间切换时触发。如果我切换到记事本,我希望 Deactivate 被触发,但它没有发生。如果我切换到 excel 窗口,从记事本以同样的方式,我希望激活被触发,但它没有发生。看起来该行为表明窗口是 MDI 子窗口。

现在我要做的是获取 Excel 主窗口的 HWnd 并使用 dllimport 功能挂钩窗口激活和停用。

谁能指导我这个。

问候

【问题讨论】:

【参考方案1】:

我在编写 Excel 插件时解决了类似的问题。不需要 dll 导入。我使用 System.Windows.Forms.NativeWindow 类解决了这个问题。

首先,我创建了我自己的类继承自 NativeWindow 类,并在其中声明了两个事件 Activated 和 Deactivate,最后重写了 WndProc() 方法以在将消息 WM_ACTIVATE 传递给 WndProc 方法时引发这些事件。根据“Message”参数,WParm 是 Excel 窗口激活还是停用。

 public class ExcelWindow: NativeWindow

    public const int WM_ACTIVATED = 0x0006;

    public ExcelWindow():base()

    //events
    public event EventHandler Activated;
    public event EventHandler Deactivate;

    //catching windows messages
    protected override void WndProc(ref Message m)
    
        if (m.Msg== WM_ACTIVATED)
        
            if (m.WParam.ToInt32() == 1)
            
                //raise activated event
                if (Activated!=null)
                
                     Activated(this, new EventArgs());
                
            
            else if (m.WParam.ToInt32() == 0)
            
                //raise deactivated event
                if (Deactivate!=null)
                
                     Deactivate(this, new EventArgs());
                
            
        
        base.WndProc(ref m);
    

然后我在我的插件类字段“ExcelWindow myExcelWindow”中创建并在我的插件的 OnConnection 方法中添加了以下代码:

ExcelWindow myExcelWindow;
void Extensibility.IDTExtensibility2.OnConnection(object application, Extensibility.ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)

    excel = application as Excel.Application;
    myExcelWindow = new ExcelWindow();
    myExcelWindow.AssignHandle(new IntPtr(excel.Hwnd));
    myExcelWindow.Activated += new EventHandler(myExcelWindow_Activated);
    myExcelWindow.Deactivate += new EventHandler(myExcelWindow_Deactivate);

    //addin code here



void myExcelWindow_Activated(object sender, EventArgs e)

    //do some stuff here

void myExcelWindow_Deactivate(object sender, EventArgs e)

    //do some stuff here

希望对你有帮助。

【讨论】:

这太棒了,你知道在 Word/PowerPoint 中有没有办法做到这一点?更具体地说,这些应用程序是否有 .Hwnd 类型的属性?【参考方案2】:

最后我找到了一个解决方案..它只适用于激活/停用。 这不是完美的方法。但我没有找到任何好的选择。 此方法使用轮询。我必须每隔 10 毫秒调用一次以下函数来检查焦点输入/输出。

public static bool ApplicationIsActivated()
    
        var activatedHandle = GetForegroundWindow();
        if (activatedHandle == IntPtr.Zero)
        
            return false;       // No window is currently activated
        

        var procId = Process.GetCurrentProcess().Id;
        int activeProcId;
        GetWindowThreadProcessId(activatedHandle, out activeProcId);

        return activeProcId == procId;
    

【讨论】:

以上是关于C#:Excel 2007 插件,如何挂钩 Windows 激活和停用事件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中将文件导出到 excel 2007+

打包一个excel插件

如何使用 VSTO 插件项目轻松创建 Excel UDF

设置 Font.Color 时 Excel 2007 VSTO 插件异常

使用 C# 从 Excel 2007 批量上传 SQL 服务器时出错

Excel 2007 VSTO 加载项即使在成功安装后也不可见