在 Windows 窗体中使用 C++ 类会导致 System.AccessViolationException

Posted

技术标签:

【中文标题】在 Windows 窗体中使用 C++ 类会导致 System.AccessViolationException【英文标题】:Using A C++ Class In Windows Form Leads to System.AccessViolationException 【发布时间】:2012-07-05 16:58:33 【问题描述】:

我编写了一些使用各种 C++ 库的 C++ 类。我制作了一个 Windows 窗体项目,并将其设置为成功使用我的类。但是,我最近制作了另一个 C++ 类,现在我一直得到:

A first chance exception of type 'System.AccessViolationException' occurred in TEST_OCU.exe

导致:

 An unhandled exception of type 'System.TypeInitializationException' occurred in Unknown Module.
 Additional information: The type initializer for '<Module>' threw an exception.

程序甚至还没有开始运行,新的导致问题的 C++ 类甚至还没有构建。如果我注释掉 new 调用,并且只有一个指向这个新 C++ 类的指针,那么一切都编译得很好。但是,如果我在某个地方做类似的事情:

 if(new_class_ptr != NULL)
    new_class_ptr->SomeFunction()  //It doesn't matter what function this is

这将再次引发这些违规行为


一些事实:

编译链接没问题,这似乎是运行时问题。 我的解决方案使用非托管 C++ 库和类(我编写的),以及一个托管 C++ 表单。 到目前为止,我还没有遇到任何问题,我已经成功使用了一些 C++ 库一段时间。这是由我最近编写的一个新的 C++ 类引起的。 导致这些违规的 C++ 类使用std::ifstream 读取文件。如果我将 std::ifstream input_file(filename); 注释掉,我的 Forms 项目就会成功运行。 如果我在一个简单的 Win32 项目中使用 C++ 类,它可以通过 std::ifstream 正常编译和运行。 我有一种强烈的感觉,它与this question有关

有人可以提供任何建议吗?谢谢


编辑:我提供了我的表单代码的某些部分。 RTSPConnection 工作得很好,有问题的类是 RTPStream

public ref class Form1 : public System::Windows::Forms::Form

public:
  // ... Lots of generated code here ...

//Calls I've written
    private: static RTSPConnection * rtsp_connection_ = NULL; //This class works
    private: static RTPStream * rtp_connection_ = NULL; //This class does not
    bool streaming_;
    System::Threading::Thread^ streaming_thread_;

    private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) 
        if(rtsp_connection_ == NULL)
        
            rtsp_connection_ = new RTSPConnection("rtsp://192.168.40.131:8554/smpte");
            streaming_ = false;
        

            //if(rtp_connection_ == NULL)
            //   rtp_connection_ = new RTPStream("test");

    

    private: System::Void Form1_FormClosing(System::Object^  sender, System::Windows::Forms::FormClosingEventArgs^  e) 
        if(rtsp_connection_ != NULL)
            rtsp_connection_->StopStreaming();
    

    private: System::Void button1_MouseClick(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) 
        if(!streaming_)
        
            //Start Streaming
            streaming_thread_ = gcnew Thread(gcnew ThreadStart(&Form1::WorkerThreadFunc));
            streaming_thread_->Start();

            this->button1->Text = L"Stop Streaming";
            streaming_ = true;
        
        else
        
            //Stop Streaming
            if(rtsp_connection_ != NULL)
            rtsp_connection_->StopStreaming();

            //THIS CALL RIGHT HERE WILL THROW AN ACCESS VIOLATION
            if(rtp_connection_ != NULL)
                rtp_connection_->StopStreaming();
            this->button1->Text = L"Start Streaming";
             streaming_ = false;
        
    
 ;

【问题讨论】:

你需要调试它。项目+属性,调试选项卡,勾选“启用非托管代码调试”选项。调试 + 异常,勾选 Win32 异常的抛出框。 找不到这个,我在VS2010上。 ***.com/questions/11091356/… 将调试器类型设置为“混合”。 如果你有相互依赖的静态类成员并且它们没有按照你期望的顺序初始化,你会在 C# 中得到几乎相同的错误。在 C++ 中,如果您有一个静态单例和另一个引用它的静态成员,如果该成员在单例之前初始化,则在初始化模块时会出现此错误。您的类或源文件是否有任何静态数据? 【参考方案1】:

这两个陈述似乎相互矛盾:

该程序甚至还没有开始运行,而新的, 导致问题的 C++ 类甚至还没有被构建。

如果我注释掉新调用,并且只有一个指向这个新 C++ 的指针 类,一切都编译得很好。

问:您能否将代码贴在您称之为“新”的地方?或者你是在说“新”——也许你只是说“如果我注释掉我的新课程”?

问:能否在构造函数中设置断点,查看堆栈跟踪,看看是谁在调用它? 什么时候

========== 附录==========

我强烈反对这种说法:

这一切都取决于这一行:std::ifstream input_file(filename); 其中文件名是 std::string。

我强烈同意此声明:

如果你有静态类成员,你会在 C# 中得到几乎相同的错误 它们相互依赖,它们没有按照你的顺序初始化 预计。在 C++ 中,如果你有一个静态单例和另一个静态 提到它的成员

调用“ifstream”本身不是问题。相反,在程序初始化之前以某种方式调用调用 ifstream 的类是问题。

问:你在这门课上叫“新”吗?如果有,在哪里。请剪切/粘贴该代码。

根据 MSDN,您应该能够设置“混合模式调试”。我有很多不同的 MSVS 副本 :) ...但 MSVS 2010/C++ 并不是其中之一。请查看此文档:

http://msdn.microsoft.com/en-us/library/fz5w87ad.aspx

http://msdn.microsoft.com/en-us/library/cktt23yw

【讨论】:

嗨,我做到了。断点永远不会到达。简单地在代码中使用构造函数会导致问题,即使它从未达到过。注释掉构造函数,将我的 ptr 设置为 NULL 并执行 if(ptr != NULL) ptr-&gt;SomeFunction() 会引发相同的错误。 问:您是否在 MSVS IDE 中明确“启用非托管调试”?问:您使用的是 MSVS 2010 Pro(或更高版本)还是 MSVS 2010 Express?您使用的是 C++/CLI(托管代码)还是非托管代码? Hans Passant 也建议,但是,我在项目属性页面中找不到该选项。我正在为它们使用托管代码 Form,但它使用的是我编写的非托管 c++ 库。其中大部分工作,如果我使用std::ifstream,这个最新的就不行了 @Constantin - 我添加了一些新信息。请不要关注“std::ifstream”...可能的例外情况是,您正在调用 ifstream 的 16 位 Unicode 版本,但代码需要 8 位 ASCII 版本(或相反亦然)。但我认为你的时间最好花在 1)让调试器工作,以及 2)找到静态对象实例我很确定你正在创建(过早创建!)恕我直言......请发布更多代码,它是甚至远程适用... Paul,我让调试器工作了,遗憾的是我使用的第三方 C++ 库没有附带调试编译的库。因此,我调用第三方库的库也被编译为“发布”。 Paul,我认为您对 8 位 ASCII 和 16 位 ASCII 有所了解。主要是因为我从我的应用程序中删除了所有构造函数调用。我将修改上面的代码以显示。

以上是关于在 Windows 窗体中使用 C++ 类会导致 System.AccessViolationException的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual C++ 中的 Windows 窗体应用程序上使用 OpenGL

在 C# WPF 或 Windows 窗体应用程序中使用 DirectX c++ DLL

如何检查是不是所有字段都已填写? [C++,VS 2015,Windows 窗体]

Windows 窗体应用程序:访问其他窗体中的元素 Visual Studio 2012 C++

CommonOpenFileDialog 导致 Windows 窗体缩小

C# Windows 窗体无法在 Windows10 上加载非托管 C++ DLL