过程在循环中启动(url),而不是启动每个实例

本文关键字:启动 实例 循环 url 过程 | 更新日期: 2023-09-27 17:58:07

我需要使用Process连续启动多个浏览器实例/选项卡。启动(url)我发现不是每个url都启动了。

    for (int i = 0; i < n; i++)
    {
        var p = Process.Start("http://localhost/#" + i.ToString());
    }

对于任何值n>1,我发现只有最后一个URL在浏览器中打开(我正在用IE作为默认浏览器进行测试)。如果我添加线程。处理后睡眠(1000)。从那时开始,我看到了各种各样的行为:有时所有的n都被创建了;有时是子集。

以下操作确实按预期工作,但假设IE(宁愿使用默认浏览器)并启动n个浏览器实例而不是n个选项卡:

    for (int i = 0; i < n; i++)
    {
        var p = Process.Start("iexplore.exe", "http://localhost/#" + i.ToString());
    }

我更愿意让它和默认的浏览器行为一起工作,但需要它具有确定性。

过程在循环中启动(url),而不是启动每个实例

似乎是一个windows资源管理器错误。你可以尝试找到常见的浏览器可执行文件并使用它们(如果存在),如果找不到匹配的文件,你可以回到默认方法。

另请参阅使用Process(可能重复)打开IE9中的多个选项卡

我们正在为IE9研究这个问题。这似乎奏效了。

bool isLaunched = false;
foreach (string url in urls)
{
    try
    {
        if (!isLaunched)
        {
            Process p = new Process();
            p.StartInfo.FileName = browser;
            p.StartInfo.Arguments = url;
            p.Start();
            Thread.Sleep(1000);
            isLaunched = true;
        }
        else
        {
            Process.Start(url);
        }
    }
    catch (Exception ex)
    {
// something
    }
}

根据我的经验,p.WaitForIdle不起作用。此外,如果浏览器实例已经在计算机上打开,则行为也会有所不同。调用iexplore实际上会将url传递给打开的实例并退出调用的进程。

我完全在处理这个问题,但它开始了。源自@tofutim的回答。基本上,使用锁定并使用计时器监视进程状态。当然,这在很大程度上取决于能否确定该过程是否已成功启动,该过程正在用进行测试

if (p.HasExited == false && p.Id != 0){ }

完整的解决方案:

bool isLaunching = false;
object launchingLock = new object();
Process p = null;
Timer timer = new Timer(new TimerCallback((state) =>
{
    lock (launchingLock)
    {
        if (isLaunching)
        {
            if (p != null && p.HasExited == false && p.Id != 0)
            {
                // Success! 
                isLaunching = false;
                Monitor.PulseAll(launchingLock);
            }
            else if(p != null && p.HasExited)
            {
                // Some sort of failure code/notification?
                // We still want to pulse though, otherwise thread will be forever kept waiting
                isLaunching = false;
                Monitor.PulseAll(launchingLock);
            }
        }
    }
}));
timer.Change(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
foreach (string url in urls)
{
    try
    {
        lock (launchingLock)
        {
            isLaunching = true;
            p = new Process();
            p.StartInfo.FileName = browser;
            p.StartInfo.Arguments = url;
            p.Start();
            // Wait until the process has finished starting before moving on
            Monitor.Wait(launchingLock);
        }
    }
    catch (Exception ex)
    {
        // something
    }
}
timer.Dispose();

最终得到了以下仍然不理想的结果(启动多个浏览器窗口),结合了命令行arg解析解决方案在C#中将包含命令行参数的字符串拆分为字符串[]

const int n = 3;
static void Main(string[] args)
{
    for (int i = 0; i < n; i++)
    {
        var start = GetDefaultBrowserStartInfo("http");
        start.Arguments += string.Format(" http://localhost/#{0}", i);
        var p = Process.Start(start);
    }
}
static ProcessStartInfo GetDefaultBrowserStartInfo(string scheme)
{
    string command = null;
    using (var key = Registry.ClassesRoot.OpenSubKey(string.Format(@"{0}'shell'open'command", scheme)))
    {
        command = (string)key.GetValue("");
    }
    string[] parsed = CommandLineToArgs(command);
    return new ProcessStartInfo
    {
        FileName = parsed[0],
        Arguments = string.Join(" ", parsed.Skip(1).ToArray()),
    };
}
[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW(
    [MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);
static string[] CommandLineToArgs(string commandLine)
{
    int argc;
    var argv = CommandLineToArgvW(commandLine, out argc);
    if (argv == IntPtr.Zero)
        throw new System.ComponentModel.Win32Exception();
    try
    {
        var args = new string[argc];
        for (var i = 0; i < args.Length; i++)
        {
            var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
            args[i] = Marshal.PtrToStringUni(p);
        }
        return args;
    }
    finally
    {
        Marshal.FreeHGlobal(argv);
    }
}

}