C#错误“尝试读取或写入受保护的内存”或“外部组件已抛出exception”

我有一个C#程序(目标框架.NET 4.0),它调用COM对象(非托管代码),正确管理所有对象,不再需要时销毁,等等。

我也有一些exception处理程序,没有自定义exception的try / catch块。 然而有时候这个程序崩溃了,大部分时间都是随机行为。 堆栈跟踪也有所不同,例如:

System.AccessViolationException was unhandled Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Source=System.Windows.Forms StackTrace: at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at IndexerTester.Program.Main() in D:\Tester\Program.cs:line 17 InnerException: 

在Program.cs中,第17行:Application.Run(new Form1());

 System.Runtime.InteropServices.SEHException was unhandled Message=External component has thrown an exception. Source=System.Windows.Forms ErrorCode=-2147467259 StackTrace: at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at IndexerTester.Program.Main() in D:\Tester\Program.cs:line 17 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException: 

我处于隔离阶段,找出这个错误的根源。

  • 你对这个错误有什么建议吗?
  • 有关捕获这些exception并优雅退出的任何建议。

谢谢你的帮助。

exception的来源是无人值守的代码,很可能是您的COM组件。 堆栈跟踪指示exception在您的消息循环中捕获,这可能是由.NET代码进行跨公寓调用到STA(单线程单元)中的COM对象的结果。 然后对方法调用进行封送处理,并使用Windows消息将其发送到组件。

进行跨公寓调用没有任何问题,但我看到一些COM组件在从不同的公寓发出指针时没有正确编组,并且通常对COM中的线程规则一无所知。 如果你的应用程序中有任何类型的multithreading,你一定要看看这个。 从主STA线程调用时,这些“损坏”的COM对象将表现良好,但在不同线程上调用或创建时可能会失败。

更具体一点:假设启动时应用程序UI线程进入STA(单线程单元)并创建COM组件。 然后创建一个新线程(将在另一个公寓中),并从该线程调用COM组件上的方法。 这是一个跨公寓电话。 您的COM组件只能在UI线程(它所在的公寓的线程)上执行。 COM框架会注意到您正在进行跨公寓呼叫,它会将呼叫序列化为缓冲区(用COM术语编组呼叫)。 然后使用Windows消息将此缓冲区发送到UI线程。 如果您的应用程序没有窗口,COM将创建一个隐藏窗口来接收这些消息。 然后,应用程序的消息循环将解压缩编组调用并在UI线程上执行它。

现在,让我们假设你或COM组件不理解COM公寓和编组规则。 方法调用中的一个参数是指针或某种解析为指针的东西,并且该指针在COM组件的单元中无效。 然后,当COM组件解析指针时,您会收到错误。 .NET运行时将检测到这一点并抛出您看到的两种exception类型之一。 但是,在UI线程的消息循环中抛出此exception,您无权访问某些代码。 在调用者处使用try-catch块无助于捕获exception,因为它在另一个线程上抛出。 无论如何,你不应该抓住exception,因为它表明你的应用程序中发生了一些非常糟糕的事情。

对于记录,错误代码-2147467259是0x8004005,转换为E_FAIL。 不是很有帮助,但您遇到的错误很可能是由于COM组件中使用了无效指针。

要解决此问题,您必须正确使用COM组件和/或修复组件中的任何损坏代码。

您的一个COM组件正在导致exception,如下所示:

Message =外部组件抛出exception

这两行应该可以帮助您找到导致问题的COM组件和被调用方法:

  at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) 

我认为你已经编写了一个包装器来连接这些COM组件? 或者您使用直接调用呼叫?

也许InnerException信息会为您提供更多详细信息。

基本上寻找您可能认为与这些COM组件相关的任何内容。