C# ShellWindows和OutOfMemoryException?
我有一个在Internet Explorer中打开URL的方法。如果已打开internet explorer,则应在新选项卡中打开它。如果没有,它应该打开一个新的internet explorer 我的代码:C# ShellWindows和OutOfMemoryException?,c#,memory-leaks,out-of-memory,C#,Memory Leaks,Out Of Memory,我有一个在Internet Explorer中打开URL的方法。如果已打开internet explorer,则应在新选项卡中打开它。如果没有,它应该打开一个新的internet explorer 我的代码: public static void OpenURL(string Url) { bool already_navigated = false; ShellWindows instances = new ShellWindows();
public static void OpenURL(string Url)
{
bool already_navigated = false;
ShellWindows instances = new ShellWindows();
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}
}
public static void OpenURL(string Url)
{
bool already_navigated = false;
ShellWindows instances = new ShellWindows();
/*
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}*/
}
public static void OpenURL(string Url)
{
bool already_navigated = false;
/*
ShellWindows instances = new ShellWindows();
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}*/
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}
}
这太棒了!但是当我调用这段代码时,我的内存在无限循环中增加,直到我得到一个OutOfMemoryException
经过一些尝试和错误,我发现这段代码抛出了一个异常:
public static void OpenURL(string Url)
{
bool already_navigated = false;
ShellWindows instances = new ShellWindows();
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}
}
public static void OpenURL(string Url)
{
bool already_navigated = false;
ShellWindows instances = new ShellWindows();
/*
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}*/
}
public static void OpenURL(string Url)
{
bool already_navigated = false;
/*
ShellWindows instances = new ShellWindows();
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}*/
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}
}
而此代码没有:
public static void OpenURL(string Url)
{
bool already_navigated = false;
ShellWindows instances = new ShellWindows();
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}
}
public static void OpenURL(string Url)
{
bool already_navigated = false;
ShellWindows instances = new ShellWindows();
/*
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}*/
}
public static void OpenURL(string Url)
{
bool already_navigated = false;
/*
ShellWindows instances = new ShellWindows();
//Check if there is an Internet Explorer
if (instances.Count > 0)
{
foreach (InternetExplorer ie in instances)
{
if (ie.Name == "Windows Internet Explorer")
{
if (!already_navigated)
{
//Navigate and open in New Tab
already_navigated = true;
ie.Navigate(Url, 0x10000);
//Bring window to front
IntPtr hwnd = (IntPtr)ie.HWND;
WindowHandler.Window w = new WindowHandler.Window(hwnd, "Internet Explorer");
w.Minimize();
w.Restore();
}
}
}
}*/
//No internet explorer found!
if (!already_navigated)
{
//Start new Internet Explorer
Process proc = Process.Start("IExplore.exe", Url);
}
}
这只给我留下了一个结论,问题在于:
ShellWindows instances = new ShellWindows();
但在谷歌搜索之后,我找不到有类似问题的人。所以我不确定我是否做错了什么,或者我在这个问题上是否是对的
有人知道发生了什么吗?此代码应该适用于您:
public static void OpenURL(string Url)
{
var t = Type.GetTypeFromProgID("Shell.Application");
dynamic o = Activator.CreateInstance(t);
try
{
var instances = o.Windows();
// Check if there is an Internet Explorer
if (instances.Count > 0)
{
for (int i = 0; i < instances.Count; i++)
{
var ie = instances.Item(i);
if (ie == null) continue;
var path = System.IO.Path.GetFileName((string)ie.FullName);
if (path.ToLower() == "iexplore.exe")
{
//Navigate and open in New Tab
ie.Navigate(Url, 0x10000);
return;
}
}
}
}
finally
{
Marshal.FinalReleaseComObject(o);
}
//No internet explorer found. Start a new onr
Process.Start("IExplore.exe", Url);
}
publicstaticvoidopenurl(字符串Url)
{
var t=Type.GetTypeFromProgID(“Shell.Application”);
动态o=Activator.CreateInstance(t);
尝试
{
var实例=o.Windows();
//检查是否有Internet Explorer
如果(instances.Count>0)
{
for(int i=0;i
ShellWindows是一个COM对象。您依赖垃圾收集器来释放RCWs(运行时可调用包装器),并由其终结器处理
但是,当您的代码只调用OpenUrl()而不做其他任何事情时,这将无法很好地工作。垃圾收集器仅在分配托管对象时运行。如果您不这样做,并且您发布的代码没有做很多这方面的工作,那么您将面临耗尽非托管内存(COM对象使用的那种内存)的巨大风险
这种情况很容易诊断,请使用Perfmon.exe并查看.NET CLR内存的性能计数器。“Gen 0 Collections”计数器显示执行Gen 0垃圾收集的频率。如果该计数器在代码运行时没有经常更改,则很可能出现OOM kaboom
这就是GC.Collect()存在的原因,计算您创建的“ie”实例的数量,并以某种神奇的数字调用Collect。Marshal.ReleaseComObject()也有帮助,通常会带来更多的麻烦,但在这里应该可以轻松操作。在你的循环中使用break
ShellWindows的另一个方面是它是一个单元线程COM对象。一个昂贵的词,意味着它不是线程安全的。这在COM中很重要,它代表对象负责线程安全。如果此代码不在Winforms或WPF应用程序的主线程上运行,您很可能会遇到麻烦。像控制台模式的应用程序或服务。或者,如果您在工作线程上运行此代码
对于公寓线程COM对象来说,这不是一个愉快的家,它需要一个STA线程来满足线程安全要求。COM将处理这个问题,它将创建一个新线程来给对象一个安全的家。当您创建了许多寿命过长的对象时,这可能会失控。也很容易诊断,打开非托管调试并关注“调试+窗口+线程”窗口。我们不知道您的代码的其余部分在做什么,但是当代码运行一段时间后,看到数百个线程就意味着厄运。每个线程为其堆栈占用一兆字节的虚拟内存,消耗32位进程所需的时间不超过几千。通过在Main()方法上应用[STAThread]属性,或者在启动线程之前对线程调用SetApartmentState()来修复此问题。我打赌这是内存泄漏。在C#中听起来很奇怪,但是是的,你为什么不在不同的点上打破它,看看哪一个喜欢增加了内存的使用@AnnArbor87我无法真正调试,因为目前我无法在我用来开发的机器上测试代码。我只能通过更改代码和记录发生的情况来进行调试。尝试注释掉代码的其他部分,如内部IF(!ready_navigated)并发布发生的情况,我认为您遇到的问题是因为IE对象。你会关闭Instance吗?你想实现什么?那没什么区别。只有当我删除ShellWindows行时,它才不会导致内存泄漏。当我尝试执行你的代码时,我出现了两个错误。第一个声明指出,为了使用“using”shell,Windows必须可转换为System.IDisposable。第二个错误是,我无法将[]索引应用于ShellWindows的表达式。我很好奇在应用程序每次运行期间调用OpenURL()的次数和次数?您的应用程序是控制台应用程序、Windows(UI桌面)还是什么?请尝试使用删除第一个应用程序,保留foreach,但应用其余建议。请尝试我刚才添加的代码。它在我的机器上工作,正如你所期望的。在它开始变大之前,我只叫它一次。我只使用.NET4.0,但我发现你的答案非常有用。谢谢你,我成功了!我所做的是在OpenURL中创建一个新线程,启动它并在STA中加入它。这似乎处理得很好!