I have a small launcher program, it loads a Splash screen on it’s own thread and displays it. If a set of conditions are met it needs to launch another application and keep the splash screen visible till the other application says it is ok to close the splash screen.

The Launcher will always have a lifetime that starts before Child App and ends after Child App closes.
Here is some snippets of relevant code
The common DLL:
namespace Example.Common
{
public partial class SplashScreen : Form
{
public SplashScreen()
{
InitializeComponent();
}
static SplashScreen splashScreen = null;
static Thread thread = null;
static public void ShowSplashScreen()
{
// Make sure it is only launched once.
if (splashScreen != null)
return;
thread = new Thread(new ThreadStart(SplashScreen.ShowForm));
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
// A static entry point to launch SplashScreen.
static private void ShowForm()
{
splashScreen = new SplashScreen();
Application.Run(splashScreen);
}
// A static method to close the SplashScreen
static public void CloseForm()
{
splashScreen.Close();
}
}
}
The Inital Launcher:
/// <summary>
/// This application is a small launcher to launch the real graphical launcher. It is small and lightweight and should be rarely be updated.
/// It will call the ProgramLauncher, the program launcher will return in it's status code the PID of the instance it launched or -1
/// if no subsequent program was started.
/// </summary>
[STAThread]
static void Main()
{
//Show the Splash screen;
Example.Common.SplashScreen.ShowSplashScreen();
//(Snip)
if (rights == UserRights.None)
{
SplashScreen.CloseForm();
MessageBox.Show("Your user does not have permission to connect to the server.", "Unable to logon", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
//If the user has full desktop access, give it to them and launch a new instance of the launcher.
else if (rights.HasFlag(UserRights.FullDesktopAccess))
{
Process explorer = new Process();
explorer.StartInfo.FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe");
if (explorer.Start() == false)
{
MessageBox.Show("Explorer failed to start.");
}
else
{
//Close the splash screen.
SplashScreen.CloseForm();
//If the user can shadow start a new instance of the launcher inside explorer.
if (rights.HasFlag(UserRights.ShadowNormalUser) || rights.HasFlag(UserRights.ShadowDemoUser))
{
//Start a new copy of the program so people can use it to shadow easily.
var shadowProc = new Process();
shadowProc.StartInfo.FileName = "ProgramLauncher.exe";
shadowProc.StartInfo.UseShellExecute = false;
shadowProc.Start();
}
explorer.WaitForExit();
}
}
else
{
Process programLauncher = new Process();
programLauncher.StartInfo.FileName = "ProgramLauncher.exe";
programLauncher.StartInfo.UseShellExecute = false;
//Launch the graphical launcher.
programLauncher.Start();
programLauncher.WaitForExit();
//Check to see if the graphical launcher launched some other process.
if (programLauncher.ExitCode >= 0)
{
//If there was a pid, don't close the micro launcher till after it closes.
Process runningProcess = Process.GetProcessById(programLauncher.ExitCode);
runningProcess.WaitForExit();
}
}
}
What is the easiest way to let ProgramLauncher close the SplashScreen instance MicroLauncher created?
You need to have
SplashScreenpass it’s window handle (HWND) toProgramLauncher. Then,ProgramLaunchercan use theSendMessagewinapi function to send aWM_SYSCOMMANDmessage to the target window:In WinForms, you can get a form’s native handle with
Handle.The platform invoke code for
SendMessageis here.At least I don’t see an easier way now, but I think it’s easier than any IPC mechanism out there.