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

发布于 2024-07-26 06:02:34 字数 418 浏览 2 评论 0原文

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

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

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

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

谁能在这方面指导我。

问候

I am writing an Excel 2007 Addin. using VS2008 and .net 3.5, C#.

I catched Microsoft.Office.Interop.Excel.Application's WindowActivate and WindowDeActivate events.

It was surprised to know that WindowActivate and Deactivate only triggers when i switch between two Excel Windows. if i switch to notepad, i expect Deactivate to be triggered, but its not happening. same way from notepad if i switch to excel window, i expect Activate to be triggered but its not happening. It looks like the behaviour indicates windows are MDI-Child windows.

Now what i want to do is get HWnd of Excel's Mainwindow and hook Window Activate and Deactivates using dllimport features.

Can anyone guide to me on this.

Regards

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

疏忽 2024-08-02 06:02:34

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

首先,我创建了自己的类,继承自 NativeWindow 类,并在其中声明了两个事件 Activated 和 Deactivate,最后重写了 WndProc() 方法,以在消息 WM_ACTIVATE 传递给 WndProc 方法时引发这些事件。 根据“消息”参数,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
}

我希望这会对您有所帮助。

I solved similar problem when writing Excel addin. No dll import is needed. I solved this issue using System.Windows.Forms.NativeWindow class.

At first, I made my own class inherited from NativeWindow class and declared two events Activated and Deactivate in it and finaly overrided WndProc() method to rise these events when message WM_ACTIVATE is passed to the WndProc method. According to "Message" parameter WParm is Excel window activated or deactivated.

 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);
    }
}

Then I made in my addin class field "ExcelWindow myExcelWindow" and added following code to OnConnection method of my addin:

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
}

I hope this will help you.

々眼睛长脚气 2024-08-02 06:02:34

最后我找到了一种解决方案......仅适用于激活/停用。
这不是完美的方法。 但我没有找到任何好的替代方案。
该方法使用轮询。 我必须每隔 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;
    }

Finally I found one solution..that works only Activate/Deactivate.
This is not the perfect way to do it. But I did not find any good alternative.
This method uses polling. I have to call following function in each 10 ms interval to check focus in/out.

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;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文