C#错误"尝试读取或写入受保护的内存"或"外部组件引发异常"

Din*_*Din 7 c#

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

我也有一些异常处理程序,没有自定义异常的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:
Run Code Online (Sandbox Code Playgroud)

在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:
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢你的帮助.

Mar*_*age 6

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

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

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

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

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

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


Chr*_*sBD 0

您的 COM 组件之一导致了异常,如下所示:

消息=外部组件抛出异常

这两行应该可以帮助您找到导致问题的 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)
Run Code Online (Sandbox Code Playgroud)

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

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

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