Skip to content

Commit

Permalink
#8 Call WaitForInputIdle, as PinballY does it
Browse files Browse the repository at this point in the history
  • Loading branch information
JockeJarre committed Jan 24, 2024
1 parent 4e6cc3f commit 62d20b9
Showing 1 changed file with 45 additions and 4 deletions.
49 changes: 45 additions & 4 deletions VPinballX.starter/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ it under the terms of the GNU General Public License as published by
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details: <https://www.gnu.org/licenses/>.
*/

using System;
using System.Diagnostics;
using System.Threading;
using OpenMcdf;
using System.Runtime.InteropServices;
using Salaros.Configuration;
Expand Down Expand Up @@ -186,7 +187,12 @@ VPinballX.starter can therefore be used as a VPinballX.exe replacement.
else
LogToFile($"Using default version {strFileVersion} mapped to \"{vpxCommand}\"");
}
StartAnotherProgram(vpxCommand, args);

var startRetries = Int32.Parse(configFileFromPath["VPinballX.starter"]["StartSetries"] ?? "20");
bool started = StartAnotherProgram(vpxCommand, args, startRetries);
if (!started){
LogToFile($"Failed to start {vpxCommand}");
}

}
catch (ArgumentException e)
Expand All @@ -212,8 +218,9 @@ bool FileOrDirectoryExists(string name)
{
return Directory.Exists(name) || File.Exists(name);
}
void StartAnotherProgram(string programPath, string[] programArgs)
bool StartAnotherProgram(string programPath, string[] programArgs, int startRetries)
{
const int WAIT_FAILED = unchecked((int)0xFFFFFFFF);

using (Process process = new Process())
{
Expand All @@ -232,14 +239,46 @@ void StartAnotherProgram(string programPath, string[] programArgs)
}
process.StartInfo = startInfo;
process.Start();
EventWaitHandle shutdownEvent = new EventWaitHandle(false, EventResetMode.ManualReset);

Console.WriteLine(process.StandardOutput.ReadToEnd());
process.WaitForInputIdle(20 * 1000);
for (int tries = 0; tries < startRetries; ++tries)
{
// wait for "input idle" state
int result = WaitForInputIdle(process.Handle, 1000);

// if it's ready, return success
if (result == 0)
break;

// If the wait failed, pause briefly and try again. For reasons
// unknown, the wait sometimes fails when called immediately on a
// new process launched with Process.Start(), but will work if
// we give it a couple of seconds.
if (result == WAIT_FAILED)
{
Thread.Sleep(100);
continue;
}

// if the wait timed out, check if the exit event was signaled;
// if so, terminate the thread immediately
if (WaitForSingleObject(shutdownEvent.SafeWaitHandle.DangerousGetHandle(), 0) == 0)
process.Kill();
return false;
}

process.WaitForExit();
return true;
}

}

[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern int WaitForInputIdle(IntPtr hProcess, uint dwMilliseconds);

[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);

public static class Native
{
Expand Down Expand Up @@ -293,4 +332,6 @@ public static extern int MessageBoxW(
[param: MarshalAs(UnmanagedType.LPWStr)] string lpText,
[param: MarshalAs(UnmanagedType.LPWStr)] string lpCaption,
UInt32 uType);


}

0 comments on commit 62d20b9

Please sign in to comment.