次の (この投稿の PS にある) テスト コードでは、メモリ リークが発生します。このメモリ リークの問題を解決する方法を教えてください。参考までに: 私は VS2010 Prof、.NET Framework 4.0、Win7 Ultimate、および IE9 を使用しています。テスト コードは、C# コード行を使用してアクティブ化できます。
(new WebBrowser_STA_Test()).Main();
ありがとうございました。
PS WebBrowser コントロール オートメーション C# コンソール アプリケーション テスト コード:
using System;
using System.Windows.Forms;
using System.Threading;
using NUnit.Framework;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace R_and_D_TestConsole
{
public class WebBrowserThread : IDisposable
{
private Action<string> _logger;
public WebBrowserThread(Action<string> logger)
{
_logger = logger;
}
private void log(string message)
{
if (_logger != null) _logger(message);
}
private Thread _STA_Thread;
public bool IsAlive
{
get
{
return (
_STA_Thread != null &&
_STA_Thread.IsAlive &&
!this.ThreadStoppingInProgress &&
!this.ThreadStopped
);
}
}
public void Start()
{
log("Starting WebBrowser Thread...");
_STA_Thread = new Thread(startBrowser);
_STA_Thread.Name = "WebBrowser STA Thread";
_STA_Thread.SetApartmentState(ApartmentState.STA);
_STA_Thread.Start();
}
public WebBrowserHandler WebBrowserHandler { get; private set; }
private void startBrowser()
{
log("WebBrowser Thread started.");
WebBrowserHandler = new WebBrowserHandler(_logger);
WebBrowserHandler.CreateBrowserInstance();
Application.Run();
}
public bool ThreadStoppingInProgress { get; private set; }
public bool ThreadStopped { get; private set; }
public void Stop()
{
if (ThreadStoppingInProgress) return;
try
{
ThreadStoppingInProgress = true;
log("Stopping WebBrowser Thread...");
log("Disposing WebBrowser Handler...");
WebBrowserHandler.DisposeBrowserInstance();
log("WebBrowser Handler partially disposed.");
_STA_Thread.Abort();
Application.ExitThread();
log("WebBrowser Thread stopped.");
}
finally
{
ThreadStopped = true;
ThreadStoppingInProgress = false;
}
}
public bool Disposed { get; private set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.Disposed)
{
if (disposing)
{
if (WebBrowserHandler != null)
{
WebBrowserHandler.Dispose();
WebBrowserHandler = null;
log("WebBrowser Handler object instance and its child objects disposed completely (?)");
}
_logger = null;
_STA_Thread = null;
}
this.Disposed = true;
}
}
}
public class WebBrowserHandlerBase : IDisposable
{
protected ISynchronizeInvoke _invokeHelper;
protected WebBrowser _webBrowser;
private Action<string> _logger;
public WebBrowserHandlerBase(Action<string> logger)
{
_logger = logger;
}
protected void log(string message)
{
if (_logger != null) _logger(message);
}
public bool Activated { get; private set; }
public void CreateBrowserInstance()
{
_webBrowser = new WebBrowser();
_webBrowser.Visible = true;
_webBrowser.DocumentCompleted += webBrowser_DocumentCompleted;
_webBrowser.ScriptErrorsSuppressed = true;
_invokeHelper = _webBrowser as ISynchronizeInvoke;
this.Activated = true;
}
public void DisposeBrowserInstance()
{
if (!this.Activated) return;
Action dispose = () =>
{
log("WebBrowserHandler.DisposeBrowserInstance (1)");
_webBrowser.DocumentCompleted -= webBrowser_DocumentCompleted;
// the following line results in floating runtime errors - commented...
//_webBrowser.Dispose();
log("WebBrowserHandler.DisposeBrowserInstance (2)");
};
if (_invokeHelper.InvokeRequired)
{
IAsyncResult result = _invokeHelper.BeginInvoke(dispose, null);
_invokeHelper.EndInvoke(result);
}
else dispose();
this.Activated = false;
}
public bool Disposed { get; private set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.Disposed)
{
if (disposing)
{
if (_webBrowser != null)
{
// The following line results in runtime error:
// 'COM object that has been separated from its underlying RCW cannot be used.'
//_webBrowser.Dispose();
log("Releasing WebBrowser ActiveX instance...");
if (_webBrowser.ActiveXInstance != null) Marshal.ReleaseComObject(_webBrowser.ActiveXInstance);
_webBrowser = null;
}
_logger = null;
}
this.Disposed = true;
}
}
public bool NavigationCompleted { get; protected set; }
public virtual void Navigate_Async(string url) { }
public virtual void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {}
}
public class WebBrowserHandler : WebBrowserHandlerBase
{
public WebBrowserHandler(Action<string> logger):base(logger) {}
public override void Navigate_Async(string url)
{
if (!this.Activated) throw new ApplicationException(string.Format("{0} is not yet activated.", this.GetType().Name) ) ;
Action<string> navigate = (x) =>
{
NavigationCompleted = false;
_webBrowser.Navigate(x);
};
if (_webBrowser.InvokeRequired) _webBrowser.Invoke(navigate, new object[] { url } );
else navigate(url);
}
public override void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
log(string.Format(" *** webBrowser_DocumentCompleted: {0} {1}", _webBrowser.ReadyState, e.Url));
if (NavigationCompleted) return;
NavigationCompleted = _webBrowser.ReadyState == WebBrowserReadyState.Complete;
if (NavigationCompleted)
{
log(string.Format(" *** {0} '{1}'", _webBrowser.DocumentText.Length, _webBrowser.DocumentTitle));
}
}
}
public class WebBrowser_STA_Test
{
private void log(string message)
{
System.Console.WriteLine("[{0}] - {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, message);
}
public void Main()
{
for (int i =1; i <= 10; i++)
{
test();
GC.Collect();
}
}
private void test()
{
log("Test started.");
foreach (string url in new string[]
{
"http://www.google.com",
"http://www.bing.com",
"http://www.yandex.ru"
})
{
log(string.Format("+++ TEST URL = '{0}' +++", url));
bool navigateMethodCalled = false;
using (WebBrowserThread _wbTest = new WebBrowserThread(log))
{
_wbTest.Start();
Application.DoEvents();
while (_wbTest.IsAlive)
{
if (_wbTest.IsAlive &&
_wbTest.WebBrowserHandler != null &&
_wbTest.WebBrowserHandler.Activated &&
!navigateMethodCalled)
{ navigateMethodCalled = true; _wbTest.WebBrowserHandler.Navigate_Async(url); }
if (_wbTest.IsAlive &&
_wbTest.WebBrowserHandler != null &&
_wbTest.WebBrowserHandler.NavigationCompleted) _wbTest.Stop();
Thread.Sleep(500);
}
}
log(string.Format("--- TEST URL = '{0}' ---\n", url));
}
log("Test finished.");
}
}
}