问题描述
在Windows窗体应用程序中,如果单击其中一项,则必须使用特定的文件夹打开一个新的资源管理器窗口.如果我通过
In my Windows Forms Application I have to open a new explorer window with a specific folder if one of the items is clicked. I am listening for the MouseUp event (because i already have some hit detection for which i need the click coordinates) now if i open a new explorer window by
private void listView1_MouseUp(object sender, MouseEventArgs e)
{
Process.Start(@"C:\");
}
它两次打开资源管理器窗口.它肯定与Process.Start(@"C:\");
有关,因为当我将行切换到普通控制台输出时,它仅执行一次.
it opens the explorer window twice. It has definitly something to do with the Process.Start(@"C:\");
because when i switch the line to a normal console output it is just executed once.
是否可以通过某种方式将事件标记为已处理或忽略第二次执行?
Is there some way to mark the event as already handled or just ignore the second execution?
推荐答案
这是一个 re-entrancy错误,与在代码中使用DoEvents()时遇到的错误类型非常相似.但是在这种情况下,该错误已内置到操作系统中.解决此问题的方法是Explorer,它在此代码中具有非常不寻常的激活模式.查看Process.Start()的返回值时可以看到的内容是null
.当Process.Start()实际未启动进程时发生.
This is a re-entrancy bug, very similar to the kind of bugs you get when you use DoEvents() in your code. But it this case the bug is built into the OS. Instrumental for this problem is Explorer, it has a very unusual activation mode in this code. Something you can see when you look at the return value of Process.Start(), it is null
. Happens when Process.Start() does not actually start a process.
通过使用仅第二次命中的条件断点,您可以看到运行中的错误.在非托管调试和启用符号服务器的情况下,调用堆栈如下所示:
You can see the bug in action by using a conditional break point that hits only the second time. With unmanaged debugging and the symbol server enabled, the call stack looks like this:
WindowsFormsApp1.exe!WindowsFormsApp1.Form1.listView1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) Line 19 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.OnMouseUp(System.Windows.Forms.MouseEventArgs e) Line 9140 C#
System.Windows.Forms.dll!System.Windows.Forms.ListView.WndProc(ref System.Windows.Forms.Message m) Line 6298 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) Line 14236 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) Line 14291 C#
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) Line 780 C#
[Native to Managed Transition]
user32.dll!__InternalCallWinProc@20() Unknown
user32.dll!UserCallWinProcCheckWow() Unknown
user32.dll!CallWindowProcW() Unknown
comctl32.dll!_CallNextSubclassProc@20() Unknown
comctl32.dll!_CallNextSubclassProc@20() Unknown
comctl32.dll!_MasterSubclassProc@16() Unknown
user32.dll!__InternalCallWinProc@20() Unknown
user32.dll!UserCallWinProcCheckWow() Unknown
user32.dll!DispatchMessageWorker() Unknown
user32.dll!_DispatchMessageW@4() Unknown
shell32.dll!SHProcessMessagesUntilEventsEx(struct HWND__ *,void * *,unsigned long,unsigned long,unsigned long,unsigned long) Unknown
shell32.dll!CShellExecute::_RunThreadMaybeWait(bool) Unknown
shell32.dll!CShellExecute::ExecuteNormal(struct _SHELLEXECUTEINFOW *) Unknown
shell32.dll!ShellExecuteNormal(struct _SHELLEXECUTEINFOW *) Unknown
shell32.dll!_ShellExecuteExW@4() Unknown
System.ni.dll!71db9903() Unknown
[Frames below may be incorrect and/or missing, native debugger attempting to walk managed call stack]
[Managed to Native Transition]
System.dll!System.Diagnostics.ShellExecuteHelper.ShellExecuteFunction() Unknown
System.dll!System.Diagnostics.ShellExecuteHelper.ShellExecuteOnSTAThread() Unknown
System.dll!System.Diagnostics.Process.StartWithShellExecuteEx(System.Diagnostics.ProcessStartInfo startInfo) Unknown
System.dll!System.Diagnostics.Process.Start() Unknown
System.dll!System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo startInfo) Unknown
System.dll!System.Diagnostics.Process.Start(string fileName) Unknown
WindowsFormsApp1.exe!WindowsFormsApp1.Form1.listView1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) Line 19 C#
SHProcessMessagesUntilEventsEx()
函数是做坏事的人,拼写"DoEvents"并实现也许等待"的漫长路途,这会导致重新输入Winforms应用程序的调度程序循环.再次检测MouseUp条件并重新触发事件处理程序.
It is the SHProcessMessagesUntilEventsEx()
function that is the evil-doer, the long way to spell "DoEvents" and implements the "maybe wait", it causes the dispatcher loop of your Winforms app to be re-entered. Detecting the MouseUp condition again and re-triggering the event handler.
您无法修复操作系统,但解决方法是导致重新进入问题的事件处理程序的通用解决方案,您可以使用BeginInvoke()彻底延迟棘手的代码,以便它在之后立即运行事件已处理.像这样:
You can't fix the OS but the workaround is the universal one for event handlers that cause re-entrancy problems, you can cleanly delay the tricky code with BeginInvoke() so that it runs immediately after the event is handled. Like this:
private void listView1_MouseUp(object sender, MouseEventArgs e) {
this.BeginInvoke(new Action(() => {
Process.Start(@"C:\");
}));
}
这篇关于使用Process.Start()时,WindowsForm MouseUp会触发两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!