【问题标题】:Adding button to another application disappears将按钮添加到另一个应用程序消失
【发布时间】:2019-12-12 07:25:19
【问题描述】:

我已经设法将一个按钮添加到另一个应用程序,在本例中,它是用于测试目的的记事本。

var w1 = NativeMethods.GetShellWindow();

        if (w1 != IntPtr.Zero)
        {
            var hWndNotepad = TopLevelWindowUtils.FindWindow(wh => wh.GetWindowText().Contains("Notepad"));


            IntPtr hWndEdit = NativeMethods.FindWindowEx(hWndNotepad.RawPtr, IntPtr.Zero, "Edit", null);


            var button = new Button { Text = "Click Me!", Left = 5, Top = 5, Width = 75, Height = 75 };
            button.Click += (o, args) => { MessageBox.Show("You've clicked me"); };

            NativeMethods.SetParent(button.Handle, hWndEdit);
            btHandle = button.Handle;
            btns.Add(button);

            Timer timer = new Timer();
            timer.Interval = (1 * 1000); // 10 secs
            timer.Tick += Timer_Tick;
            timer.Start();

        }

这很好,我在记事本中看到了按钮:

但是,当我失去窗口焦点、最小化等时,按钮就会消失。我如何保留它?

我尝试在计时器上发送消息以重新绘制,但它不起作用:

private void Timer_Tick(object sender, EventArgs e)
    {
        var w1 = NativeMethods.GetShellWindow();

        if (w1 != IntPtr.Zero)
        {
            var hWndNotepad = TopLevelWindowUtils.FindWindow(wh => wh.GetWindowText().Contains("Notepad"));
            IntPtr hWndEdit = NativeMethods.FindWindowEx(hWndNotepad.RawPtr, IntPtr.Zero, "Edit", null);

            NativeMethods.SendMessage(btHandle, NativeMethods.WM_PAINT, IntPtr.Zero, IntPtr.Zero);

        }
    }

你能帮忙吗?

PS。我试图将其作为 Windows 服务运行,以便在服务运行时,它始终在其他应用程序中具有按钮 - 在本例中为记事本。

【问题讨论】:

  • 我们可以提供帮助,但这不是您想要的帮助:这无法可靠地完成。
  • 当然从服务进程中获得零机会,在会话 0 中隔离运行。但即使是用户桌面上的进程也无法可靠地实现这一点。无论您的问题是什么,这都不是解决方案。
  • 按钮不应在编辑框中创建,即使您拥有该进程。编辑框想要在该区域进行绘制。我不知道您的目标是什么,也许您想从头开始编写自己的简单记事本程序,带有工具栏按钮,必须有可用的示例 .net 示例。
  • @BarmakShemirani 这只是测试解决方案
  • 你可以看一下这个例子stackoverflow.com/a/36455629/4603670,它在标题栏中添加了一个按钮(不是标准按钮类)。虽然我个人不会尝试该代码,但它会出现太多问题并且可能导致其他进程崩溃。我建议找到一个更标准的解决方案,例如使用托盘图标等。

标签: c# winforms winapi


【解决方案1】:

所以我想我做到了:

private void Timer_Tick(object sender, EventArgs e)
    {
        var w1 = NativeMethods.GetShellWindow();

        if (w1 != IntPtr.Zero)
        {
            var hWndNotepad = TopLevelWindowUtils.FindWindow(wh => wh.GetWindowText().Contains("Notepad"));
            IntPtr hWndEdit = NativeMethods.FindWindowEx(hWndNotepad.RawPtr, IntPtr.Zero, "Edit", null);

            NativeMethods.SendMessage(btHandle, NativeMethods.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero);
            NativeMethods.SendMessage(btHandle, NativeMethods.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);

        }
    }

我尝试了不同的消息 - 我以 100 毫秒的循环运行此计时器。

我不是专家,有什么缺点?

【讨论】:

  • 缺点太多,无法一一列举。 无法解决的缺点是:通过允许用户触发应用程序中的事件,您的按钮最终必须是有用的。该事件通常以WM_COMMAND 消息的形式传递,使用控件 ID 来标识操作。您无法找到不会与您的目标应用程序发生冲突的唯一控件ID。
  • 当然,还有一个非常明显的缺点:不断地将焦点设置在一个 100 毫秒计时器上的控件上,这会完全破坏您的键盘界面和大部分鼠标界面。并且忽略了,您不会永远发送WM_SETFOCUS 消息;该消息由系统发送,作为焦点导航的一部分。
  • @IInspectable - 如果我的按钮单击只是打开具有特定 URL 的 Internet Explorer 浏览器会发生什么?
  • 这没什么区别,什么你想要实现。重要的是,如何实现它。而这个问题没有可靠的解决方案。
猜你喜欢
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多