如何构建C++;捕捉所有异常的Dll包装器? 就像标题所说的,我们正在寻找一种方法来捕捉来自C++代码的所有异常,并将其封装在DLL中。通过这种方式,我们可以保护使用此dll的应用程序的安全,使其不受此dll中发生的任何错误的影响 但是,在Windows下C++似乎是不可能的。p>

如何构建C++;捕捉所有异常的Dll包装器? 就像标题所说的,我们正在寻找一种方法来捕捉来自C++代码的所有异常,并将其封装在DLL中。通过这种方式,我们可以保护使用此dll的应用程序的安全,使其不受此dll中发生的任何错误的影响 但是,在Windows下C++似乎是不可能的。p>,c++,winapi,exception,visual-c++,C++,Winapi,Exception,Visual C++,例如: void function() { try { std::list<int>::iterator fd_it; fd_it++; } catch(...) {} } void函数() { 尝试 { std::list::迭代器fd_it; fd_it++; }捕获(…){} } 例外的情况不被标准C++尝试/ catch块捕获,也不被任何代码SE>翻译器函数所设置。相反,DLL崩溃,使

例如:

void function()
{  
    try  
    {    
        std::list<int>::iterator fd_it;
        fd_it++;  
    } catch(...) {}
}
void函数()
{  
尝试
{    
std::list::迭代器fd_it;
fd_it++;
}捕获(…){}
}

例外的情况不被标准C++尝试/ catch块捕获,也不被任何代码SE>翻译器函数所设置。相反,DLL崩溃,使用DLL的程序中止。我们使用Visual C++ 2005编写了选项/SHA.有没有人知道,在C++和Win32中有可能捕捉到这些问题并生成ROCKSOLL DLL包装器吗?< /P> < P>在标准的LabBar容器上增加迭代器将不会抛出C++异常。在Windows上,C++有2种不同的异常类型:C++和SEH异常。p> SEH是一种仅限windows的异常形式(有点类似于UNIX中的信号)。这更像是一个系统级的异常。对于无效指针访问、对齐问题等操作,将抛出它们

<>如果你想捕捉Windows上C++应用程序所能抛出的所有异常,你需要同时捕获这两个异常。幸运的是,有一种方法可以混合使用C++和SEH异常。我最近写了一篇关于这方面的详细博客,它应该会帮助你


您看过windows API函数SetUnhandledExceptionFilter吗


我通常在DllMain函数中调用它,并在DLL崩溃时让它生成一个小型转储。但是:(a)我不知道它是否会捕获应用程序异常和DLL异常,以及(b)我不知道是否可以让处理程序以这样的方式返回,以使程序执行能够继续。文档说是的,但我从来没有这样做过。

制作一个坚如磐石的DLL包装器的唯一方法是在另一个进程中加载有缺陷的DLL,这样,如果它崩溃了,它就不会让您的主进程崩溃

捕获所有C++异常似乎是合理的,但捕捉所有结构化异常是另一回事。SEH似乎在大部分方面都能帮到您,因为它允许您捕获访问冲突、除以零异常等

但是,如果错误的DLL碰巧接触到另一个线程堆栈中的未提交页面,该怎么办?内存访问将出现页面错误,将调用异常处理程序,现在该页面不再是保护页面。当该线程需要增加堆栈时,它将获得访问冲突,进程将崩溃。(请更详细地描述此案例。)

另一个可能的问题是:错误的DLL在保存同步对象时崩溃,但您使用SEH捕获异常。如果您的进程试图获取相同的同步对象,那么它会死锁而不是崩溃。共享同步对象可能是C运行时或操作系统的一部分:如果buggy DLL 1加载buggy DLL 2,当buggy DLL 1持有加载程序锁时,它在其
DllMain()
中崩溃,该怎么办?您的进程下次加载DLL时会死锁吗

有关这(以及类似问题的函数,如
IsBadReadPtr()
)为何误用SEH的更多信息,请参见:

  • 拉里·奥斯特曼的博客:
  • 拉里·奥斯特曼的博客:
  • 拉里·奥斯特曼的博客:
  • 新旧事物:
此代码包含逻辑错误(如果有)。由于逻辑错误构成错误,因此不要吞下异常–修复错误


当然,这是特定于特定代码的。其他人则提出了更一般的建议。然而,我发现很多人实际上更喜欢捕捉异常而不是修复逻辑错误,这是完全不能接受的。

下面的代码取自IDE。它将捕获所有Windows生成的异常:

步骤#1:定义异常筛选函数

  DWORD ExceptionFilter(EXCEPTION_POINTERS *pointers, DWORD dwException)
  {
    //-- we handle all exceptions
    DWORD dwResult = EXCEPTION_EXECUTE_HANDLER;

    switch (dwException)
    {
      case EXCEPTION_ACCESS_VIOLATION:
      case EXCEPTION_DATATYPE_MISALIGNMENT:
      case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
      case EXCEPTION_FLT_DENORMAL_OPERAND:
      case EXCEPTION_FLT_DIVIDE_BY_ZERO:
      case EXCEPTION_FLT_INEXACT_RESULT:
      case EXCEPTION_FLT_INVALID_OPERATION:
      case EXCEPTION_FLT_OVERFLOW:
      case EXCEPTION_FLT_STACK_CHECK:
      case EXCEPTION_FLT_UNDERFLOW:
      case EXCEPTION_INT_DIVIDE_BY_ZERO:
      case EXCEPTION_INT_OVERFLOW:
      case EXCEPTION_PRIV_INSTRUCTION:
      case EXCEPTION_NONCONTINUABLE_EXCEPTION:
      case EXCEPTION_BREAKPOINT:
        dwResult = EXCEPTION_EXECUTE_HANDLER;
        break;
    }

    return dwResult;
  }
第2步:将代码包装为“尝试”和“尝试”,如下所示除外:

  __try
  {
    // call your dll entry point here
  }
  __except(ExceptionFilter(GetExceptionInformation(), 
                           GetExceptionCode()))
  {
    //-- display the fatal error message
    MessageBox(0, "An unexpected error was caught here!", 
               "Unexpected Error", MB_OK);
  }

捕捉到异常(特别是SEH异常)后,您将做什么

实际上,您不能对流程的状态做出任何假设,实际上您唯一的选择是(可选地)转储核心并退出


从长远来看,任何尝试和操作都绝对会给您带来问题。

康拉德·鲁道夫:当然,这段代码包含一个“逻辑错误”,它是为了说明可能发生的问题。就像那个人说的,他希望能够保护他的dll免受任何可能的错误。你不认为这是一个合理的问题吗?听说过供应商的产品。我们中的一些人生活在现实世界中,生活在现实问题中。解决其他人的问题是不可能的

它会抛出一个结构化异常,这是Microsoft编译器的事情。对于那些你能捕捉到的除数为零,内存访问不良等等。。。语义不同于C++异常,这是标准C++中的未定义行为,当然我并不反对。只是指出在VC++中,它实际上会抛出一些可以被捕获的东西(…)。但这不是标准C++,任何异常都不等于错误。这只是个例外。它们发生了,这就是它们存在的原因。这是否明智的原则将是一个遥远的话题。(不是风扇,打开第二个程序流路径)。未捕获的异常可能导致错误。如果没有其他合适的位置来捕获异常,那么可以在最高级别捕获它。只要捕获到异常,这是完全可以接受的。@thewhiteambit我不是说一般情况,我是说OP的特定代码。我在这里看不到特定代码。也许是第三方DLL,他不能