过程在循环中启动(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());
}
我更愿意让它和默认的浏览器行为一起工作,但需要它具有确定性。
似乎是一个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);
}
}
}