C# 打开进程(记事本)后如何将焦点设置回表单?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8881038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set focus back to form after opening up a process (Notepad)?
提问by nawfal
I open up a notepad from my program using Process.Start()but the new opened notepad covers the screen. But I do want my application to maintain its focus.
我从我的程序中打开了一个记事本,Process.Start()但新打开的记事本覆盖了屏幕。但我确实希望我的应用程序保持其重点。
I similarly (using the same Process.Start) open up MS Excel and Word but to get focus back to my form all I need to write is:
我同样(使用相同的 Process.Start)打开 MS Excel 和 Word,但为了让焦点回到我的表单,我需要写的是:
this.Focus();
But quirk with Notepad: I open notepad (and all other processes like this)
但是记事本的怪癖:我打开记事本(以及所有其他类似的进程)
Process process = new Process();
process.StartInfo.UseShellExecute = true;
process.EnableRaisingEvents = true;
process.StartInfo.FileName = @"abc.log";
process.Start();
Now notepad takes the focus.
现在记事本成为焦点。
I tried these:
我试过这些:
this.Activate(),this.Focus(), needless to mention[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] public static extern IntPtr SetFocus(HandleRef hWnd); { IntPtr hWnd = myProcess.Handle; SetFocus(new HandleRef(null, hWnd)); }[DllImport("User32")] private static extern int SetForegroundWindow(IntPtr hwnd); [DllImportAttribute("User32.DLL")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); private const int SW_SHOW = 5; private const int SW_MINIMIZE = 6; private const int SW_RESTORE = 9; { ShowWindow(Process.GetCurrentProcess().MainWindowHandle, SW_RESTORE); SetForegroundWindow(Process.GetCurrentProcess().MainWindowHandle); }Another lengthier solution got from here.
this.Activate(),this.Focus()不用提[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] public static extern IntPtr SetFocus(HandleRef hWnd); { IntPtr hWnd = myProcess.Handle; SetFocus(new HandleRef(null, hWnd)); }[DllImport("User32")] private static extern int SetForegroundWindow(IntPtr hwnd); [DllImportAttribute("User32.DLL")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); private const int SW_SHOW = 5; private const int SW_MINIMIZE = 6; private const int SW_RESTORE = 9; { ShowWindow(Process.GetCurrentProcess().MainWindowHandle, SW_RESTORE); SetForegroundWindow(Process.GetCurrentProcess().MainWindowHandle); }另一个更长的解决方案是从这里得到的。
All which still keeps the focus on notepad. Why is it so difficult to merely get focus to a window, that too application's own window?
所有这些仍将重点放在记事本上。为什么仅仅将焦点放在一个窗口上如此困难,那也是应用程序自己的窗口?
EDIT: At best I can open the notepad minimized, but it still wouldn't give the focus to the form after trying all the above codes. Notepad opens minimized, but focus will be still on notepad (something that sometimes we see in windows xp) and form will be out of focused.
编辑:充其量我可以打开最小化的记事本,但在尝试上述所有代码后,它仍然不会将焦点放在表单上。记事本打开最小化,但焦点仍会在记事本上(有时我们在 windows xp 中会看到这种情况)并且表单将失去焦点。
采纳答案by nawfal
I tried almost everything on internet (so sure about it :)). At best I could get my form on top of all other forms, but without focus (going by @Hans Passant's method). Going by heavy blocks of codes all over, I somehow felt this aint gonna be easy. So I always used SetForegroundWindow()with chunks of other code. Never thought merely SetForegroundWindow()would do the trick.
我几乎尝试了互联网上的所有内容(非常确定:))。充其量我可以将我的表格放在所有其他表格之上,但没有焦点(通过@Hans Passant 的方法)。通过大量的代码块,我不知何故觉得这不会很容易。所以我总是使用SetForegroundWindow()其他代码块。从来没有想过只是SetForegroundWindow()会做伎俩。
This worked.
这奏效了。
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
private void button1_Click(object sender, EventArgs e)
{
Process process = new Process();
process.StartInfo.FileName = @...\abc.log";
process.Start();
process.WaitForInputIdle(); //this is the key!!
SetForegroundWindow(this.Handle);
}
At times this method yields in a focus on the parent form (in cases where my desired form is a modal child form of its parent form); in such cases, just add this.Focus()to the last line..
有时,这种方法会产生对父表单的关注(在我想要的表单是其父表单的模态子表单的情况下);在这种情况下,只需添加this.Focus()到最后一行..
Even this worked:
即使这有效:
Microsoft.VisualBasic.Interaction.Shell(@"notepad.exe D:\abc.log",
Microsoft.VisualBasic.AppWinStyle.NormalNoFocus);
Solution provided by here
此处提供的解决方案
回答by hcb
I had the same problem, i eventually wound up with programmatically calling alt-tab:
我遇到了同样的问题,我最终以编程方式调用 alt-tab:
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private void alttab()
{
uint WM_SYSCOMMAND = 0x0112;
int SC_PREVWINDOW = 0xF050;
PostMessage(Process.GetCurrentProcess().MainWindowHandle, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
}
//EDIT: You should use process.MainWindowHandle instead ofcourse
//编辑:你应该使用 process.MainWindowHandle 而不是 ofcourse
回答by Hans Passant
Windows prevents apps from shoving their window into the user's face, you are seeing this at work. The exact rules when an app may steal the focus are documented in the MSDN docs for AllowSetForegroundWindow().
Windows 阻止应用程序将它们的窗口推到用户的脸上,您在工作中看到了这一点。应用程序可能窃取焦点的确切规则记录在 AllowSetForegroundWindow() 的 MSDN 文档中。
A back-door around this restriction is the AttachThreadInput() function. This code worked well, I did take a shortcut on finding the thread ID for the thread that owns the foreground window. Good enough for Notepad, possibly not for other apps. Do beware that Raymond Chen does notapprove of this kind of hack.
围绕此限制的一个后门是 AttachThreadInput() 函数。这段代码运行良好,我确实采用了快捷方式来查找拥有前台窗口的线程的线程 ID。对于记事本来说已经足够好了,但对于其他应用程序可能就不行了。一定要提防雷蒙德陈并没有认可这种破解的。
private void button1_Click(object sender, EventArgs e) {
var prc = Process.Start("notepad.exe");
prc.WaitForInputIdle();
int tid = GetCurrentThreadId();
int tidTo = prc.Threads[0].Id;
if (!AttachThreadInput(tid, tidTo, true)) throw new Win32Exception();
this.BringToFront();
AttachThreadInput(tid, tidTo, false);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool AttachThreadInput(int tid, int tidTo, bool attach);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
回答by Lito
Try this:
尝试这个:
public partial class MainForm : Form
{
private ShowForm showForm;
public MainForm()
{
InitializeComponent();
}
private void showButton_Click(object sender, EventArgs e)
{
this.showForm = new ShowForm();
this.showForm.FormClosed += showForm_FormClosed;
this.showForm.Show(this);
}
private void showForm_FormClosed(object sender, FormClosedEventArgs e)
{
this.Focus();
}
}

