0

I'm working on an application that starts other processes (some console applications, etc.). Each process has a user interface. When each process is started (via process.Start()), I want to move the process UI to some other location on the screen (also on the second monitor). I know how to do this later after a "sleep" or button click action. The problem is that I want the window to move right after the process starts. The window handle is still not "available" (value is 0).

I searched for a solution and came across the process.WaitForExit(100) method and the process.Exited event handler. After investigating these, I discovered that:

  • the process.Exited event is called when the process ends and not when the process "loads," and

  • process.WaitForExit(100) causes the program to "sleep" when it is invoked.

So, I need some architecture guidance. How can I solve my problem without "sleeping" (for example, via process.WaitForExit(100))? Should I consider an approach that involves one of the following techniques:

  • Mutex,
  • Multithreading, or
  • Async process start?

Or, is process.WaitForExit(100) really OK (not "dangerous") for a stable application (if I will run up to 15 processes)? Here is my code example:

private void startApplication(
    int aApplicationId,
    string aBrowserPath,
    string aAppPath,
    int aMid,
    int aAppLeft,
    int aAppTop,
    int aAppWidth,
    int aAppHeight) // Try to start application process 
{
    Process process = new Process();

    try
    {
        process.StartInfo.FileName = aAppPath;

        //process.EnableRaisingEvents = true;
        //process.Exited += new EventHandler(myProcess_Exited);
        //process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;                

        process.Start();
        process.WaitForExit(100);

        mProcessMap.Add(aApplicationId, process); // Add to process map

        // Move process window to right position
        IntPtr windowHandle = process.MainWindowHandle;

        this.moveAppToRightPosition(windowHandle, aMid, aAppLeft, aAppTop,
            aAppWidth, aAppHeight);
    }
    catch (Exception exc)
    {
        Console.WriteLine("ERROR! Process start exception!");
    }
}
DavidRR
  • 18,291
  • 25
  • 109
  • 191
StormRider
  • 42
  • 7
  • Not necessarily an answer, but a possible solution. If there is a possibility, you can use parametrized start of the new process (you can send window position?), this way you can avoid flickering of the window (presummably you want to avoid this issue). –  Aug 17 '17 at 11:51
  • Will the value of `process.MainWindowHandle` always be `null`? If not, you could spin wait for the handle to become available with a `while (process.MainWindowHandle == null) ;` statement. Once it completes you will have a non-null handle. – Will Custode Aug 17 '17 at 11:54

3 Answers3

1

Sleeping might not be the right way, because the process might need more time to start.

It may be possible to start a thread (if you want to asynchronously run the function startApplication) and in that thread check for the state of the process and when available set the position of window (looping with sleep at the end of loop).

1

You can't retrieve the MainWindowHandle immediately after the process is created because the creation of a process and of a window are two completely independent things (not to mention that a process may not even have a window). So there is nothing wrong with sleeping and waiting for the MainWindowHandle to appear. MSDN says you need to call Refresh to update it.

If you don't want to sleep you have two options:

  1. Set a hook that will notify you when the process created a window. More details in this answer.
  2. If you also created the process you are launching then you can insert the logic that will notify the master process via a socket or named pipe once the window is created.
Andrey
  • 59,039
  • 12
  • 119
  • 163
0

I would use SendMessageTimeout to send WM_NULL messages in a loop, with a small timeout of say 50-100ms. If the function succeeds, that means that the new process is alive and going strong. In this way, you will block only for the timeout interval.

Nick
  • 4,787
  • 2
  • 18
  • 24