【转】CLR20R3程序终⽌的⼏种解决⽅案
这是因为.NET Framework 1.0 和 1.1 这两个版本对许多未处理异常(例如,线程池线程中的未处理异常)提供⽀撑,⽽ Framework 2.0 版中,公共语⾔运⾏库允许线程中的多数未处理异常⾃然继续。在多数情况下,这意味着未处理异常会导致应⽤程序终⽌。
⼀、C/S 解决⽅案(以下任何⼀种⽅法)
1. 在应⽤程序配置⽂件中,添加如下内容:
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="true" />
</runtime>
</configuration>
2. 在应⽤程序配置⽂件中,添加如下内容:
<configuration>
<startup>
<supportedRuntime version="v1.1.4322"/>
</startup>
</configuration>
3. 使⽤Application.ThreadException事件在异常导致程序退出前截获异常。⽰例如下:
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
public static void Main(string[] args)
{
Application.ThreadException += new ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);    Application.Run(new ErrorHandlerForm());
}
// 在主线程中产⽣异常
private void button1_Click(object sender, System.EventArgs e)
{
throw new ArgumentException("The parameter was invalid");
oracle10g程序异常终止
}
// 创建产⽣异常的线程
private void button2_Click(object sender, System.EventArgs e)
{
ThreadStart newThreadStart = new ThreadStart(newThread_Execute);
newThread = new Thread(newThreadStart);
newThread.Start();
}
// 产⽣异常的⽅法
void newThread_Execute()
{
throw new Exception("The method or operation is not implemented.");
}
private static void Form1_UIThreadException(object sender, ThreadExceptionEventArgs t)
{
DialogResult result = DialogResult.Cancel;
try
{
result = ShowThreadExceptionDialog("Windows Forms Error", t.Exception);
}
catch
{
try
{
MessageBox.Show("Fatal Windows Forms Error",
"Fatal Windows Forms Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);
}
finally
{
Application.Exit();
}
}
if (result == DialogResult.Abort)
Application.Exit();
}
// 由于 UnhandledException ⽆法阻⽌应⽤程序终⽌,因⽽此⽰例只是在终⽌前将错误记录在应⽤程序事件⽇志中。private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try
{
Exception ex = (Exception)e.ExceptionObject;
string errorMsg = "An application error occurred. Please contact the adminstrator " +
"with the following information:/n/n";
if (!EventLog.SourceExists("ThreadException"))
{
EventLog.CreateEventSource("ThreadException", "Application");
}
EventLog myLog = new EventLog();
myLog.Source = "ThreadException";
myLog.WriteEntry(errorMsg + ex.Message + "/n/nStack Trace:/n" + ex.StackTrace);
}
catch (Exception exc)
{
try
{
MessageBox.Show("Fatal Non-UI Error",
"Fatal Non-UI Error. Could not write the error to the event log. Reason: "
+ exc.Message, MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
finally
{
Application.Exit();
}
}
}
private static DialogResult ShowThreadExceptionDialog(string title, Exception e)
{
string errorMsg = "An application error occurred. Please contact the adminstrator " +
"with the following information:/n/n";
errorMsg = errorMsg + e.Message + "/n/nStack Trace:/n" + e.StackTrace;
return MessageBox.Show(errorMsg, title, MessageBoxButtons.AbortRetryIgnore,
MessageBoxIcon.Stop);
}
⼆、B/S 解决⽅案(以下任何⼀种⽅法)
1. 在IE⽬录(C:/Program Files/Internet Explorer)下建⽴fig⽂件,内容如下:
<?xml version="1.0"?>
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="true" />
</runtime>
</configuration>
2. 不建议使⽤此⽅法,这将导致使⽤ framework 1.1 以后版本的程序在IE中报错。
建⽴同上的配置⽂件,但内容如下:
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v1.1.4322"/>
</startup>
</configuration>
3. 这个⽐较繁琐,分为三步:
⑴. 将下⾯的代码保存成⽂件,⽂件名为UnhandledExceptionModule.cs,路径是C:/Program Files/Microsoft Visual Studio 8/VC/ using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Web;
namespace WebMonitor {
public class UnhandledExceptionModule: IHttpModule {
static int _unhandledExceptionCount = 0;
static string _sourceName = null;
static object _initLock = new object();
static bool _initialized = false;
public void Init(HttpApplication app) {
// Do this one time for each AppDomain.
if (!_initialized) {
lock (_initLock) {
if (!_initialized) {
string webenginePath = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "webengine.dll");
if (!File.Exists(webenginePath)) {
throw new Exception(String.Format(CultureInfo.InvariantCulture,
"Failed to locate webengine.dll at '{0}'.  This module requires .NET Framework 2.0.",
webenginePath));
}
FileVersionInfo ver = FileVersionInfo.GetVersionInfo(webenginePath);
_sourceName = string.Format(CultureInfo.InvariantCulture, "ASP.NET {0}.{1}.{2}.0",
ver.FileMajorPart, ver.FileMinorPart, ver.FileBuildPart);
if (!EventLog.SourceExists(_sourceName)) {
throw new Exception(String.Format(CultureInfo.InvariantCulture,
"There is no EventLog source named '{0}'. This module requires .NET Framework 2.0.",
_sourceName));
}
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);                        _initialized = true;
}
}
}
public void Dispose() {
}
void OnUnhandledException(object o, UnhandledExceptionEventArgs e) {
// Let this occur one time for each AppDomain.
if (Interlocked.Exchange(ref _unhandledExceptionCount, 1) != 0)
return;
StringBuilder message = new StringBuilder("/r/n/r/nUnhandledException logged by UnhandledExceptionModule.dll:/r/n/r/nappId=");            string appId = (string) AppDomain.CurrentDomain.GetData(".appId");
if (appId != null) {
message.Append(appId);
}
Exception currentException = null;
for (currentException = (Exception)e.ExceptionObject; currentException != null; currentException = currentException.InnerException) {
message.AppendFormat("/r/n/r/ntype={0}/r/n/r/nmessage={1}/r/n/r/nstack=/r/n{2}/r/n/r/n",
currentException.GetType().FullName,
currentException.Message,
currentException.StackTrace);
}
EventLog Log = new EventLog();
Log.Source = _sourceName;
Log.WriteEntry(message.ToString(), EventLogEntryType.Error);
}
}
}
⑵. 打开Visual Studio 2005的命令提⽰⾏窗⼝
输⼊ -k key.snk后回车
输⼊Type csc /t:library /r:system.web.dll,system.dll /keyfile:key.snk UnhandledExceptionModule.cs后回车
输⼊ /if UnhandledExceptionModule.dll后回车
输⼊ngen install UnhandledExceptionModule.dll后回车
输⼊gacutil /l UnhandledExceptionModule后回车并将显⽰的”强名称”信息复制下来
⑶. 打开ASP应⽤程序的fig⽂件,将下⾯的XML加到⾥⾯。注意:不包括”[]”,①可能是添加到<httpModules></httpModules>之间。
<add name="UnhandledExceptionModule" type="WebMonitor.UnhandledExceptionModule, [这⾥换为上⾯复制的强名称信息]" />
三、微软并不建议的解决⽅案
打开位于 %WINDIR%/Microsoft.NET/Framework/v2.0.50727 ⽬录下的 fig ⽂件,将属性 legacyUnhandledExceptionPolicy 的enabled 设置为 true
四、跳出三界外——ActiveX
ActiveX 的特点决定了不可能去更改每个客户端的设置,采⽤ B/S 解决⽅案⾥的第 3 种⽅法也不⾏,⾄于⾏不通的原因,我想可能是因为ActiveX 的⼦控件产⽣的异常直接
被 CLR 截获了,并没有传到最外层的 ActiveX 控件,这只是个⼈猜测,如果有清楚的朋友,还望指正。
最终,我也没到在 ActiveX 情况的解决⽅法,但这却是我最需要的,⽆奈之下,重新检查代码,发现了其中的问题:在⼦线程中创建了控件,⼜将它添加到了主线程的 UI 上。
以前遇到这种情况,系统就会报错了,这次居然可以蒙混过关,最搞不懂的是在 framework 2.0 的 C/S 结构下也没有报错,偏偏在
IE(ActiveX) ⾥挂了。唉,都是宿主惹的祸。