Process.Start 使用 UseShellExecute 无法在上一次关闭 window 后将 notepad.exe window 带到前台

Process.Start with UseShellExecute fails to bring notepad.exe window to the foreground after a previous close window

我正在尝试使用 Process.Start (with UseShellExecute=true) 创建 notepad.exe 的实例。下面的代码在另一个程序(语音输入程序)调用的 COM 对象中运行。

大多数时候代码运行良好,并按预期创建记事本实例作为新的顶部 window 焦点。如果我用 WM_CLOSE 消息关闭记事本 windows,我可以按照预期的随机顺序打开和关闭以及打开、打开、关闭、关闭、记事本 windows,如下所示:

    Win32.PostMessage(Hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);

第二种关闭记事本的方法Window

主流的第三方语音软件还提供了“关闭window”命令,可以在前台关闭记事本window。这种关闭记事本实例的方法是问题的一部分。

问题

问题是用语音命令“关闭window”关闭记事本后,下一个打开操作打开记事本但没有将其带到前台。它在 Outlook 或 Chrome 后面打开,并在任务栏上可见。出于某种原因,在使用“close window”命令关闭记事本后,Process.Start 代码不会将记事本实例带到前台。我不明白为什么。 Process.Start 代码应该不知道前一个记事本实例是如何(或是否)关闭的。

下面的代码试图 SetWindowPos 强制记事本 window 到 foreground/top 以防 Process.Start 没有完成这项工作,但是 SetWindowPos 代码永远不会失败,即使出现问题,也不会出现失败消息框。 (SetWindowPos 只是一个附带问题,因为代码通常可以很好地处理 WM_CLOSE 消息。)

可在我的机器上重现

这是我在我的机器上登录的典型模式。 FChrome/FOutlook 表示 Chrome 或 Outlook 是实验的前景 windows(两者都尝试了相同的结果)。 No = 记事本打开,Nc = 记事本关闭(同上),CW = “关闭window”,NoXX表示失败(记事本没有出现在最前面window)。

Sequences of operations: open, close, open, "close window", open (notepad open fails NoXX)
FChrome, No, Nc, No, CW, NoXX
FOutlook, No, Nc, No, CW, NoXX

有谁知道为什么 window 关闭方法(可能是 SendMessage 或 Win32.WindowDestroy?)会使 Process.Start 无法将记事本的新实例带到前台?

    // record name of foreground window before the operation
    var forehandle = GetForegroundWindow ();
    var forenamebefore = WinFuns.GetForegroundWindow ().Title;

    // create process to start notepad
    var psi = new ProcessStartInfo ();
    psi.UseShellExecute = true;
    psi.FileName = "notepad.exe";
    var proc = Process.Start (psi);
    Thread.Sleep (2000);

    // get foreground process name after Process.Start - it should be notepad
    proc.Refresh (); // refresh before retrieving the handle
    IntPtr prochandle = (IntPtr)proc.MainWindowHandle;
    var forenameafter = WinFuns.GetForegroundWindow ().Title;

    // get the process name of this code
    var myhandle = Process.GetCurrentProcess ().MainWindowHandle;
    var myname = (new WindowHandle (myhandle)).Title;

    // ensure the notepad instance is on top
    bool r;
    var p = new IntPtr (0);
    r = Win32.SetWindowPos (prochandle, p, 0, 0, 0, 0, 3); //window on top
    if (!r) MessageBox.Show ($"Failed to set top window position.");

    // show before/after/mynames after the operation is complete
    var msg = $"Foreground before: {forenamebefore}\n" +
              $"Foreground after: {forenameafter}\n" +
              $"My name is:       {myname}";
    MessageBox.Show (msg);

在又解决了这个问题几天并尝试了各种解决方案之后,我仍然无法解释为什么会出现原来的问题(用其他应用关闭记事本后无法将记事本带到最前面)。

但是,随着时间的推移,我的代码越来越大,因为我在每次 Win32 操作后检查每个 Win32 错误代码,并通过循环重试,并在必要或适当时再次尝试。

我的结论是,检查每个操作的每个 Win32 错误代码并每 100 毫秒重试失败的操作可以捕获一些失败的操作,但没有解决原始问题。