91 lines
3.2 KiB
C#
91 lines
3.2 KiB
C#
|
|
using System.Diagnostics;
|
||
|
|
using System.IO;
|
||
|
|
|
||
|
|
namespace TeamsISO.App.Services;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Small Win32 wrapper that launches the Microsoft Teams desktop client as a
|
||
|
|
/// subprocess of TeamsISO. First step toward Phase E.1 of the embedded-Teams
|
||
|
|
/// roadmap (see docs/superpowers/specs/2026-05-08-embedded-teams-orchestration.md):
|
||
|
|
/// the operator can launch Teams from within TeamsISO so they don't have to
|
||
|
|
/// switch apps to start a meeting.
|
||
|
|
///
|
||
|
|
/// The launcher tries (in order):
|
||
|
|
/// 1. ms-teams: URI (works for both classic and new Teams)
|
||
|
|
/// 2. MSTeams.exe in %LOCALAPPDATA%\Microsoft\WindowsApps\
|
||
|
|
/// 3. Teams.exe in %LOCALAPPDATA%\Microsoft\Teams\Update.exe (legacy)
|
||
|
|
///
|
||
|
|
/// Group-routing automation (writing NDI Access Manager config so Teams
|
||
|
|
/// broadcasts on a private group) is deferred to a follow-up — for v1.0 we
|
||
|
|
/// document the manual steps in RELEASING.md and trust the operator to set
|
||
|
|
/// them once per machine.
|
||
|
|
/// </summary>
|
||
|
|
public static class TeamsLauncher
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Launches Teams. Returns true if a launch was started successfully (the
|
||
|
|
/// process may take a few seconds to actually appear). False if every
|
||
|
|
/// fallback path failed.
|
||
|
|
/// </summary>
|
||
|
|
public static bool TryLaunch(out string? errorMessage)
|
||
|
|
{
|
||
|
|
errorMessage = null;
|
||
|
|
|
||
|
|
// Path 1: URI scheme. The shell handler picks whichever Teams client
|
||
|
|
// is registered (new MSTeams.exe takes priority on modern Windows).
|
||
|
|
if (TryStart("ms-teams:", useShell: true)) return true;
|
||
|
|
|
||
|
|
// Path 2: new Teams' WindowsApps shim.
|
||
|
|
var newTeams = Path.Combine(
|
||
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||
|
|
"Microsoft", "WindowsApps", "ms-teams.exe");
|
||
|
|
if (File.Exists(newTeams) && TryStart(newTeams, useShell: false)) return true;
|
||
|
|
|
||
|
|
// Path 3: classic Teams Update.exe with --processStart hands off to
|
||
|
|
// the actual Teams.exe via Squirrel.
|
||
|
|
var classicUpdater = Path.Combine(
|
||
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||
|
|
"Microsoft", "Teams", "Update.exe");
|
||
|
|
if (File.Exists(classicUpdater))
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
Process.Start(new ProcessStartInfo
|
||
|
|
{
|
||
|
|
FileName = classicUpdater,
|
||
|
|
Arguments = "--processStart \"Teams.exe\"",
|
||
|
|
UseShellExecute = false,
|
||
|
|
CreateNoWindow = true,
|
||
|
|
});
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
errorMessage = ex.Message;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
errorMessage ??= "No Microsoft Teams installation was found. Install Teams from https://www.microsoft.com/microsoft-teams and try again.";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static bool TryStart(string target, bool useShell)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var info = new ProcessStartInfo
|
||
|
|
{
|
||
|
|
FileName = target,
|
||
|
|
UseShellExecute = useShell,
|
||
|
|
CreateNoWindow = true,
|
||
|
|
};
|
||
|
|
Process.Start(info);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|