透過な起動

以前のエントリであるClickOnceと非ClickOnceのアプリケーションを透過に起動するでも言及したが、最終的にはスタンドアロンのアセンブリとClickOnceで配布されたアセンブリを、透過に起動できればよいので、考えてみた。
以前も書いたが、ClickOnceアセンブリを起動する際に介在するブラウザウインドウを開かないことと、配布形態により、コマンドラインパラメタの引継ぎの方法が違う(ClickOnceはURLのクエリパラメタで渡す必要がある)のを吸収してやるのがミソだ。

class UniversalLaunch
{
    static void Main(string args)
    {
        if ( args.Length == 0 )
        {
            System.Console.WriteLine(@"""起動パス"" ""起動パラメタ""で起動してくれ");
            System.Environment.Exit(0);
        }
        /* arg[0]は起動パス(url)、arg[1]以降はコマンドラインパラメタとする */
        string targetPath = args[0];
        string subArgs = new string[args.Length - 1];
        Array.ConstrainedCopy(args, 1, subArgs, 0, args.Length - 1);
        
        Process proccess = new Process();
        ProcessStartInfo startInfo = new ProcessStartInfo(targetPath);

        string ext = Path.GetExtension(targetPath);
        switch(ext)
        {
            case ".application":
                /* IEから起動 */
                startInfo.FileName = "IExplore.EXE";
                string argStr = CombineArgumentFor('&', subArgs);
                startInfo.Arguments = (argStr != null)
                                          ? targetPath + "?" + argStr
                                          : targetPath;
                startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                break;
            case ".exe" :
                startInfo.Arguments = CombineArgumentFor(' ', subArgs);
                startInfo.UseShellExecute = false;
                break;
        }
        proccess.StartInfo = startInfo;
        proccess.Start();
        
    }
    private static string CombineArgumentFor(char delim, string[] args)
    {
        if ( args == null || args.Length == 0 ) return null;
        StringBuilder bd = new StringBuilder();
        foreach (string arg in args)
        {
            bd.Append(arg).Append(delim);
        }
        return bd.ToString().TrimEnd(delim);
    }
}

いろいろある拡張子やMIMEのことを考えるときりが無いので、通常のexeとClickOnceマニフェストだけは確実に実行できるように、それ以外は拡張子に任せた起動でも良しとしよう。