简体   繁体   English

当我将可见的正确设置为true时,如何防止我的C#winforms应用程序窃取焦点?

[英]How to prevent my C# winforms application from stealing focus when I set the visible properly to true?

I've got a C# winforms application that runs in the background, listening for hotkeys to be pressed. 我有一个在后台运行的C#winforms应用程序,正在监听要按下的热键。 When a hotkey is pressed, my form makes a brief appearance. 当按下热键时,我的表格会短暂出现。 The form is always running, but set to hidden until I receive a hotkey event, at which time I set the visible property to true. 表单始终在运行,但设置为隐藏,直到我收到热键事件,此时我将visible属性设置为true。 The code looks like this: 代码如下所示:

void hook_volumeDown(object sender, KeyPressedEventArgs e)
{
    this.Visible = true;
}

It should be noted that the topmost property of this form is set to true. 应该注意,此表单的最顶层属性设置为true。

The really odd part is, after my C# app has stolen focus from another application, it will never do it again. 真正奇怪的是,在我的C#应用​​程序从另一个应用程序中窃取焦点后,它将再也不会这样做了。 For example: I launch my app, then launch some fullscreep app like Team Fortress 2. Then I press my hotkey. 例如:我启动我的应用程序,然后启动一些像Team Fortress 2这样的fullscreep应用程序。然后我按下我的热键。 Team Fortress 2 minimizes, and I see my form. Team Fortress 2最小化,我看到了我的形式。 Then, however, I can restore TF2, and press my hotkey again all I want (with the desired effect), and TF2 will remain focused. 然而,然后,我可以恢复TF2,并再次按我的热键我想要的(具有所需的效果),TF2将保持聚焦。

At any rate, I'm looking for a way to fix this. 无论如何,我正在寻找解决这个问题的方法。 I've found a lot of questions here covering similar problems, but all of them are related to creating/launching a new form, not making an existing one visible (unless I missed something). 我在这里发现了很多关于类似问题的问题,但是所有问题都与创建/启动新表单有关,而不是使现有表单可见(除非我遗漏了一些东西)。 I could rework the application to create a new form every time I need one, but that would entail creating yet another form to be invisible all the time just to wait for hotkey events, so I'd rather leave it as it is. 我可以重新编写应用程序,以便在每次需要时创建一个新表单,但这需要创建另一个表单,以便一直看不见只是为了等待热键事件,所以我宁愿保持原样。

Any ideas? 有任何想法吗?

I think you problem is related to the fact that Visible = true behaves differently between the first and subsequent calls. 我认为你的问题与Visible = true在第一次和后续调用之间表现不同的事实有关。 The first time visible is called and the window handle has not been created, the Window is created by calling CreateWindowEx which has some style parameters which controls how the window should behave. 第一次调用visible并且尚未创建窗口句柄时,通过调用CreateWindowEx创建Window,它具有一些控制窗口行为方式的样式参数。 I think you need to make sure that the window is created with the style WS_EX_NOACTIVATE, which you can do by overriding CreateParams. 我认为您需要确保使用样式WS_EX_NOACTIVATE创建窗口,您可以通过覆盖CreateParams来完成。

Other things to try out: 其他要试试的东西:

1) The ShowWindow function (used by Visible = true) ignores the focus parameter the first time it is called ( http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx ) if the program provides a STARTUPINFO structure. 1)ShowWindow函数(由Visible = true使用)在第一次调用时忽略焦点参数( http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx )该程序提供了STARTUPINFO结构。 Dig into reflector and find out if the Form class provides a STARTUPINFO structure and if so, how to manipulate it. 深入研究反射器并找出Form类是否提供STARTUPINFO结构,如果是,则如何操作它。

2) The Form has a ShowWithoutActivation property than can be overriden and set to true, have you overriden this? 2)Form有一个ShowWithoutActivation属性,可以覆盖并设置为true,你有没有覆盖它?

Sorry for the "no exact answer", but I hope this at least gives you some starting points for further investigation. 对不起“没有确切的答案”,但我希望这至少可以为您提供一些进一步调查的起点。 Good luck. 祝好运。

Seeing KeyPressedEventArgs being used in your function looks really strange. 看到你的函数中使用的KeyPressedEventArgs看起来奇怪。 Hot keys can be implemented by P/Invoking the RegisterHotKey() API function. 热键可以通过P / Invoking RegisterHotKey()API函数实现。 It sends a message to your window when the hot key is pressed. 当按下热键时,它会向您的窗口发送一条消息。 Here's an example of a form that's invisible at start up, springs alive when you press the hot key. 这是一个在启动时不可见的表单示例,当您按下热键时弹出。 Ctrl+Alt+U in this case: 在这种情况下,按Ctrl + Alt + U:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        private const int MYKEYID = 0;    // In case you want to register more than one...
        public Form1() {
            InitializeComponent();
            this.FormClosing += (s, args) => UnregisterHotKey(this.Handle, MYKEYID);
        }
        protected override void SetVisibleCore(bool value) {
            if (value && !this.IsHandleCreated) {
                this.CreateHandle();
                RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U);
                value = false;
            }
            base.SetVisibleCore(value);
        }
        protected override void WndProc(ref Message m) {
            if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) {
                this.Visible = true;
                if (this.WindowState == FormWindowState.Minimized)
                    this.WindowState = FormWindowState.Normal;
                SetForegroundWindow(this.Handle);
            }
            base.WndProc(ref m);
        }
        // P/Invoke declarations
        private const int WM_HOTKEY = 0x312;
        private const int MOD_ALT = 1;
        private const int MOD_CONTROL = 2;
        private const int MOD_SHIFT = 4;
        [DllImport("user32.dll")]
        private static extern int RegisterHotKey(IntPtr hWnd, int id, int modifier, Keys vk);
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
    }
}

Note that the SetForegroundWindow() function is the rub, possibly also the source of the problem you describe in your question. 请注意,SetForegroundWindow()函数可能是您在问题中描述的问题的根源。 Windows doesn't permit an app to shove a window in the user's face when the user is actively using another window. 当用户正在使用其他窗口时,Windows不允许应用程序在用户的脸上推动窗口。 At least several seconds of inactivity must expire before it will allow the window to steal the focus. 至少几秒钟的不活动必须在允许窗口窃取焦点之前到期。 With the given code, that is easy enough to see, the taskbar button of your form will be blinking. 使用给定的代码,很容易看到,表单的任务栏按钮将闪烁。 Avoid setting the ShowInTaskbar property to false. 避免将ShowInTaskbar属性设置为false。 It isn't necessary to do so with this code, the taskbar button won't show up until the hot key is pressed. 没有必要使用此代码,任务栏按钮将不会显示,直到按下热键。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM