简体   繁体   中英

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

I am trying to use Process.Start (with UseShellExecute=true) to create an instance of notepad.exe . The code below runs inside of a COM object called by another program (a voice-input program).

Most of the time the code runs fine and creates the notepad instances as expected as a new top window with the focus. I can open and close and open, open, close, close, notepad windows in random order as expected if I close the notepad windows with a WM_CLOSE message as follows:

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

A Second Way of Closing the Notepad Window

The mainstream third-party voice software also provides a “close window” command that will close the notepad window when it is in the foreground. This method of closing the notepad instance is part of the problem.

The Problem

The problem is that after closing the notepad with the voice command “close window,” the next open operation opens notepad but does not bring it to the foreground. It opens behind Outlook or Chrome and is visible on the taskbar. For some reason, the Process.Start code does not bring the notepad instance to the foreground after notepad has been closed with the “close window” command. I don't understand why. The Process.Start code should have no clue how (or if) the previous notepad instance was closed.

The code below tries to SetWindowPos to force the notepad window to the foreground/top in case Process.Start did not do the job, but the SetWindowPos code never fails and the failure message box never appears, even when the problem occurs. (SetWindowPos is only a side issue, since the code normally works fine with WM_CLOSE messages.)

Reproducible on My Machine

Here is a typical pattern that I logged on my machine. FChrome/FOutlook means Chrome or Outlook were the foreground windows for the experiment (both were tried with the same results). No = notepad open, Nc = notepad close (as above), CW = “close window”, and NoXX means failure (notepad did not appear as the top foreground 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

Does anyone know why a window-closing method (maybe SendMessage or Win32.WindowDestroy?) would make Process.Start fail to bring a new instance of Notepad to the foreground?

    // 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);

After working on this problem for another few days and trying out various solution attempts, I still cannot explain why the original problem occurred (failing to bring notepad to the front after closing it with a different app).

However, over time my code grew in size as I checked every Win32 error code after every Win32 operation and retried by looping and trying again as necessary or appropriate.

I conclude that checking every Win32 error code on every operation and retrying failed operations every 100 milliseconds caught some failed operations, but did not solve the original problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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