I just recently figured the best way to do this. I pieced it together from multiple sources. This is for C# Custom action launching an exe. You can also just launch the exe by a Wix ExeCommand and use the custom action to bring it forward after manually finding the correct process.
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
static extern IntPtr GetTopWindow(IntPtr hWnd);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_SHOWWINDOW = 0x0040;
[CustomAction]
public static ActionResult BringExeForward(Session session)
{
ProcessStartInfo processInfo = new ProcessStartInfo("Application.exe");
Process bProcess = Process.Start(processInfo);
while (GetTopWindow((IntPtr)null) != bProcess.MainWindowHandle)
{
SetWindowPos(bProcess.MainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
SetWindowPos(bProcess.MainWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
return ActionResult.Success;
}